Mint on Source Chain
We will now Mint an NFT on the source Chain (Ethereum Sepolia 11155111)
MINT



CrossDestinationMinter.sol




CrossSourceMinter.sol




Last updated
We will now Mint an NFT on the source Chain (Ethereum Sepolia 11155111)











Last updated
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// Deploy this contract on Sepolia
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
interface InftMinter {
function mintFrom(address account, uint256 sourceId) external;
}
/**
* THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract CrossDestinationMinter is CCIPReceiver {
InftMinter public nft;
event MintCallSuccessfull();
// https://docs.chain.link/ccip/supported-networks/testnet
address routerSepolia = 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59;
constructor(address nftAddress) CCIPReceiver(routerSepolia) {
nft = InftMinter(nftAddress);
}
function _ccipReceive(
Client.Any2EVMMessage memory message
) internal override {
(bool success, ) = address(nft).call(message.data);
require(success);
emit MintCallSuccessfull();
}
function testMint() external {
// Mint from Sepolia
nft.mintFrom(msg.sender, 0);
}
function testMessage() external {
// Mint from Sepolia
bytes memory message;
message = abi.encodeWithSignature("mintFrom(address,uint256)", msg.sender, 0);
(bool success, ) = address(nft).call(message);
require(success);
emit MintCallSuccessfull();
}
function updateNFT(address nftAddress) external {
nft = InftMinter(nftAddress);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// Deploy this contract on Fuji
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
/**
* THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract CrossSourceMinter {
// Custom errors to provide more descriptive revert messages.
error NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance to cover the fees.
error NothingToWithdraw(); // Used when trying to withdraw but there's nothing to withdraw.
IRouterClient public router;
LinkTokenInterface public linkToken;
uint64 public destinationChainSelector;
address public owner;
address public destinationMinter;
event MessageSent(bytes32 messageId);
constructor(address destMinterAddress) {
owner = msg.sender;
// https://docs.chain.link/ccip/supported-networks/testnet
// from Fuji
address routerAddressFuji = 0xF694E193200268f9a4868e4Aa017A0118C9a8177;
router = IRouterClient(routerAddressFuji);
linkToken = LinkTokenInterface(0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846);
linkToken.approve(routerAddressFuji, type(uint256).max);
// to Sepolia
destinationChainSelector = 16015286601757825753;
destinationMinter = destMinterAddress;
}
function mintOnSepolia() external {
// Mint from Fuji network = chain[1]
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(destinationMinter),
data: abi.encodeWithSignature("mintFrom(address,uint256)", msg.sender, 1),
tokenAmounts: new Client.EVMTokenAmount[](0),
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({gasLimit: 980_000})
),
feeToken: address(linkToken)
});
// Get the fee required to send the message
uint256 fees = router.getFee(destinationChainSelector, message);
if (fees > linkToken.balanceOf(address(this)))
revert NotEnoughBalance(linkToken.balanceOf(address(this)), fees);
bytes32 messageId;
// Send the message through the router and store the returned message ID
messageId = router.ccipSend(destinationChainSelector, message);
emit MessageSent(messageId);
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function linkBalance (address account) public view returns (uint256) {
return linkToken.balanceOf(account);
}
function withdrawLINK(
address beneficiary
) public onlyOwner {
uint256 amount = linkToken.balanceOf(address(this));
if (amount == 0) revert NothingToWithdraw();
linkToken.transfer(beneficiary, amount);
}
}