测量 ccipReceive 函数的燃气消耗。一旦得到该数值,将其增加 10%,并将其作为 transferUsdc 函数的 gasLimit 参数
-
src/ccip-master-class-4 是关于 USDC 跨链的测试.参考: https://cll-devrel.gitbook.io/ccip-bootcamp/v/mandarin-ccip-bootcamp/di-3-tian/lian-xi-4-kua-lian-fa-song-usdc
-
src 目录里,与作业相关的源码位于 src/ccip-master-class-4 ,src 目录里其他子目录可忽略.
-
test/TransferUSDC.t.sol 是一个预估 ccipReceive gas limit 的测试用例
-
实现作业要求的关键流程位于:script/ccip-master-class-4/B2TransferUsdcWithDynamicFeeOnAvalancheFuji.sol
-
estimateReceiveGas 方法首先调用 test 目录里的相关方法获取 ccipReceive 的 gasLimit
-
eoa 调用 AvalancheFuji 链,将 eoa 的 usdc 代币操作授权给 TransferUSDC(0xF23C461dE16f42C88c6dCe6AC645a87EFad1a7Cc)
-
在 AvalancheFuji 链上调用合约方法 transferUSDC.transferUsdc() 将 usdc 跨链转账给 EthereumSepolia 上的 transferReceiver 合约.
-
上面第 3 步里,调用 transferUSDC.transferUsdc 时,将第 1 步获取的 gasLimit 预估值作为参数传入.
-
脚本 B2TransferUsdcWithDynamicFeeOnAvalancheFuji.sol,提交后的一个 message 信息: https://ccip.chain.link/msg/0x371cf2a9771a21214a85eaa4783e39c1226a44314fd236ee41a33a48def4a217
Note
This repository represents an example of using a Chainlink product or service. It is provided to help you understand how to interact with Chainlink’s systems so that you can integrate them into your own. This template is provided "AS IS" without warranties of any kind, has not been audited, and may be missing key checks or error handling to make the usage of the product more clear. Take everything in this repository as an example and not something to be copy pasted into a production ready service.
This project demonstrates a couple of basic Chainlink CCIP use cases.
- Install packages
forge install
and
npm install
- Compile contracts
forge build
Chainlink Cross-Chain Interoperability Protocol (CCIP) provides a single, simple, and elegant interface through which dApps and web3 entrepreneurs can securely meet all their cross-chain needs, including token transfers and arbitrary messaging.
With Chainlink CCIP, one can:
- Transfer supported tokens
- Send messages (any data)
- Send messages and tokens
CCIP receiver can be:
- Smart contract that implements
CCIPReceiver.sol - EOA
Note: If you send a message and token(s) to EOA, only tokens will arrive
To use this project, you can consider CCIP as a "black-box" component and be aware of the Router contract only. If you want to dive deep into it, check the Official Chainlink Documentation.
In the next section you can see a couple of basic Chainlink CCIP use case examples. But before that, you need to set up some environment variables.
Create a new file by copying the .env.example file, and name it .env. Fill in your wallet's PRIVATE_KEY, and RPC URLs for at least two blockchains
PRIVATE_KEY=""
ETHEREUM_SEPOLIA_RPC_URL=""
ARBITRUM_SEPOLIA_RPC_URL=""
AVALANCHE_FUJI_RPC_URL=""
POLYGON_MUMBAI_RPC_URL=""
BNB_CHAIN_TESTNET_RPC_URL=""
WEMIX_TESTNET_RPC_URL=""
KROMA_SEPOLIA_TESTNET_RPC_URL=""
METIS_SEPOLIA_RPC_URL=""
ZKSYNC_SEPOLIA_RPC_URL=""Once that is done, to load the variables in the .env file, run the following command:
source .envMake yourself familiar with the Helper.sol smart contract. It contains all the necessary Chainlink CCIP config. If you ever need to adjust any of those parameters, go to the Helper contract.
This contract also contains some enums, like SupportedNetworks:
enum SupportedNetworks {
ETHEREUM_SEPOLIA, // 0
AVALANCHE_FUJI, // 1
ARBITRUM_SEPOLIA, // 2
POLYGON_MUMBAI, // 3
BNB_CHAIN_TESTNET, // 4
OPTIMISM_SEPOLIA, // 5
BASE_SEPOLIA, // 6
WEMIX_TESTNET, // 7
KROMA_SEPOLIA_TESTNET, // 8
METIS_SEPOLIA, // 9
ZKSYNC_SEPOLIA // 10
}This means that if you want to perform some action from AVALANCHE_FUJI blockchain to ETHEREUM_SEPOLIA blockchain, for example, you will need to pass 2 (uint8) as a source blockchain flag and 0 (uint8) as a destination blockchain flag.
Similarly, there is an PayFeesIn enum:
enum PayFeesIn {
Native, // 0
LINK // 1
}So, if you want to pay for Chainlink CCIP fees in LINK token, you will pass 1 (uint8) as a function argument.
The test files are located in the test folder. Note that there are two types of tests:
-
Test with CCIPLocalSimulator: These tests are used to test the CCIP functionality in your local environment. They are located in the
test/no-forkfolder. To run these tests, run the following command:forge test --no-match-contract ".*ForkTest$"
-
Test with CCIPLocalSimulatorFork: These tests are used to test the CCIP functionality in a forked environment. They are located in the test/fork folder. To run these tests, run the following command:
forge test --match-contract ".*ForkTest$"
Note: The fork tests send CCIP messages from Arbitrum Sepolia to Ethereum Sepolia, so make sure you have the ETHEREUM_SEPOLIA_RPC_URL and ARBITRUM_SEPOLIA_RPC_URL set in your .env file.
You will need test tokens for some of the examples in this Starter Kit. Public faucets sometimes limit how many tokens a user can create and token pools might not have enough liquidity. To resolve these issues, CCIP supports two test tokens that you can mint permissionlessly so you don't run out of tokens while testing different scenarios.
To get 10**18 units of each of these tokens, use the script/Faucet.s.sol smart contract. Keep in mind that the CCIP-BnM test token you can mint on all testnets, while CCIP-LnM you can mint only on Ethereum Sepolia. On other testnets, the CCIP-LnM token representation is a wrapped/synthetic asset called clCCIP-LnM.
function run(SupportedNetworks network) external;For example, to mint 10**18 units of both CCIP-BnM and CCIP-LnM test tokens on Ethereum Sepolia, run:
forge script ./script/Faucet.s.sol -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0Or if you want to mint 10**18 units of CCIP-BnM test token on Avalanche Fuji, run:
forge script ./script/Faucet.s.sol -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8)" -- 2To transfer tokens from one EOA on one blockchain to another EOA on another blockchain you can use the script/Example01.s.sol smart contract:
function run(
SupportedNetworks source,
SupportedNetworks destination,
address receiver,
address tokenToSend,
uint256 amount,
PayFeesIn payFeesIn
) external returns (bytes32 messageId);For example, if you want to send 0.0000000000000001 CCIP-BnM from Avalanche Fuji to Ethereum Sepolia and to pay for CCIP fees in LINK, run:
forge script ./script/Example01.s.sol -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8,uint8,address,address,uint256,uint8)" -- 2 0 <RECEIVER_ADDRESS> 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 100 1To transfer tokens from EOA from the source blockchain to the smart contract on the destination blockchain, follow the next steps:
- Deploy
BasicMessageReceiver.solto the destination blockchain, using thescript/Example02.s.sol:DeployBasicMessageReceiversmart contract:
function run(SupportedNetworks destination) external;For example, to deploy it to Ethereum Sepolia, run:
forge script ./script/Example02.s.sol:DeployBasicMessageReceiver -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0- Transfer tokens, from the source blockchain to the deployed BasicMessageReceiver smart contract using the
script/Example02.s.sol:CCIPTokenTransfersmart contract:
function run(
SupportedNetworks source,
SupportedNetworks destination,
address basicMessageReceiver,
address tokenToSend,
uint256 amount,
PayFeesIn payFeesIn
) external returns (bytes32 messageId);For example, if you want to send 0.0000000000000001 CCIP-BnM from Avalanche Fuji to Ethereum Sepolia and to pay for CCIP fees in native coin (Test AVAX), run:
forge script ./script/Example02.s.sol:CCIPTokenTransfer -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8,uint8,address,address,uint256,uint8)" -- 2 0 <BASIC_MESSAGE_RECEIVER_ADDRESS> 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 100 0- Once the CCIP message is finalized on the destination blockchain, you can see the details about the latest message using the
script/Example02.s.sol:GetLatestMessageDetailssmart contract:
function run(address basicMessageReceiver) external view;For example,
forge script ./script/Example02.s.sol:GetLatestMessageDetails -vvv --broadcast --rpc-url ethereumSepolia --sig "run(address)" -- <BASIC_MESSAGE_RECEIVER_ADDRESS>- Finally, you can always withdraw received tokens from the
BasicMessageReceiver.solsmart contract using thecast sendcommand.
For example, to withdraw 100 units of CCIP-BnM previously sent, run:
cast send <BASIC_MESSAGE_RECEIVER_ADDRESS> --rpc-url ethereumSepolia --private-key=$PRIVATE_KEY "withdrawToken(address,address)" <BENEFICIARY_ADDRESS> 0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05To transfer a token or batch of tokens from a single, universal, smart contract to any address on the destination blockchain follow the next steps:
- Deploy
BasicTokenSender.solto the source blockchain, using thescript/Example03.s.sol:DeployBasicTokenSendersmart contract:
function run(SupportedNetworks source) external;For example, if you want to send tokens from Avalanche Fuji to Ethereum Sepolia, run:
forge script ./script/Example03.s.sol:DeployBasicTokenSender -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8)" -- 2- [OPTIONAL] If you want to send tokens to the smart contract, instead of EOA, you will need to deploy
BasicMessageReceiver.solto the destination blockchain. For this purpose, you can reuse thescript/Example02.s.sol:DeployBasicMessageReceiversmart contract from the previous example:
function run(SupportedNetworks destination) external;For example, to deploy it to Ethereum Sepolia, run:
forge script ./script/Example02.s.sol:DeployBasicMessageReceiver -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0- Fill the
BasicTokenSender.solwith tokens/coins for fees (you can always withdraw it later). You can do it manually from your wallet or by using thecast sendcommand.
For example, if you want to pay for Chainlink CCIP Fees in LINK tokens, you can fill the BasicTokenSender.sol smart contract with 1 Avalanche Fuji LINK by running:
cast send 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 "transfer(address,uint256)" <BASIC_TOKEN_SENDER_ADDRESS> 1000000000000000000 --rpc-url avalancheFuji --private-key=$PRIVATE_KEYOr, if you want to pay for Chainlink CCIP Fees in Native coins, you can fill the BasicTokenSender.sol smart contract with 0.1 Avalanche Fuji AVAX by running:
cast send <BASIC_TOKEN_SENDER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY --value 0.1ether- For each token you want to send, you will need to approve the
BasicTokenSender.solto spend it on your behalf, by using thecast sendcommand.
For example, if you want to send 0.0000000000000001 CCIP-BnM using the BasicTokenSender.sol you will first need to approve that amount:
cast send 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 "approve(address,uint256)" <BASIC_TOKEN_SENDER_ADDRESS> 100 --rpc-url avalancheFuji --private-key=$PRIVATE_KEY- Finally, send tokens by providing the array of
Client.EVMTokenAmount {address token; uint256 amount;}objects, using thescript/Example03.s.sol:SendBatchsmart contract:
function run(
SupportedNetworks destination,
address payable basicTokenSenderAddres,
address receiver,
Client.EVMTokenAmount[] memory tokensToSendDetails,
BasicTokenSender.PayFeesIn payFeesIn
) external;For example, to send CCIP-BnM token amounts you previously approved from Avalanche Fuji to Ethereum Sepolia, and pay for Chainlink CCIP fees in LINK tokens, run:
forge script ./script/Example03.s.sol:SendBatch -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8,address,address,(address,uint256)[],uint8)" -- 0 <BASIC_TOKEN_SENDER_ADDRESS> <RECEIVER> "[(0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4,100)]" 1- Of course, you can always withdraw tokens you sent to the
BasicTokenSender.solfor fees, or fromBasicMessageReceiver.solif you received them there.
For example, to withdraw ERC20 tokens, run:
cast send <CONTRACT_WITH_FUNDS_ADDRESS> --rpc-url <RPC_ENDPOINT> --private-key=$PRIVATE_KEY "withdrawToken(address,address)" <BENEFICIARY_ADDRESS> <TOKEN_TO_WITHDRAW_ADDRESS>And to withdraw Native coins, run:
cast send <CONTRACT_WITH_FUNDS_ADDRESS> --rpc-url <RPC_ENDPOINT> --private-key=$PRIVATE_KEY "withdraw(address)" <BENEFICIARY_ADDRESS>To transfer tokens and data across multiple chains, follow the next steps:
- Deploy the
ProgrammableTokenTransfers.solsmart contract to the source blockchain, using thescript/Example04.s.sol:DeployProgrammableTokenTransferssmart contract:
function run(SupportedNetworks network) external;For example, if you want to send a message from Avalanche Fuji to Ethereum Sepolia type:
forge script ./script/Example04.s.sol:DeployProgrammableTokenTransfers -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8)" -- 2- Open Metamask and fund your contract with Native tokens. For example, if you want to send a message from Avalanche Fuji to Ethereum Sepolia, you can send 0.1 Fuji AVAX to your contract. You can also do the same thing using the
cast sendcommand:
cast send <PROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY --value 0.1ether- Open Metamask and fund your contract with LINK tokens. For example, if you want to send a message from Avalanche Fuji to Ethereum Sepolia, you can send a 1 Fuji LINK to your contract. You can also do the same thing using the
cast sendcommand:
cast send 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 "transfer(address,uint256)" <PROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS> 1000000000000000000 --rpc-url avalancheFuji --private-key=$PRIVATE_KEY- Deploy the
ProgrammableTokenTransfers.solsmart contract to the destination blockchain, using thescript/Example04.s.sol:DeployProgrammableTokenTransferssmart contract, as you did in step number one.
For example, if you want to receive a message from Avalanche Fuji on Ethereum Sepolia type:
forge script ./script/Example04.s.sol:DeployProgrammableTokenTransfers -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0At this point, you have one sender contract on the source blockchain, and one receiver contract on the destination blockchain. Please note that ProgrammableTokenTransfers.sol can both send & receive tokens and data, hence we have two identical instances on both source and destination blockchains.
- Send a message, using the
script/Example04.s.sol:SendTokensAndDatasmart contract:
function run(
address payable sender,
SupportedNetworks destination,
address receiver,
string memory message,
address token,
uint256 amount
) external;For example, if you want to send a "Hello World" message alongside 100 units of CCIP-BnM from Avalanche Fuji to Ethereum Sepolia, type:
forge script ./script/Example04.s.sol:SendTokensAndData -vvv --broadcast --rpc-url avalancheFuji --sig "run(address,uint8,address,string,address,uint256)" -- <PROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS_ON_SOURCE_BLOCKCHAIN> 0 <PROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS_ON_DESTINATION_BLOCKCHAIN> "Hello World" 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 100- Once the CCIP message is finalized on the destination blockchain, you can see the details of the latest CCIP message received, by running the following command:
cast call <PROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS_ON_DESTINATION_BLOCKCHAIN> "getLastReceivedMessageDetails()" --rpc-url ethereumSepoliaTo send simple Text Cross-Chain Messages and pay for CCIP fees in Native Tokens, follow the next steps:
- Deploy the
BasicMessageSender.solsmart contract on the source blockchain, using thescript/Example05.s.sol:DeployBasicMessageSendersmart contract:
function run(SupportedNetworks source) external;For example, if you want to send a simple cross-chain message from Avalanche Fuji, run:
forge script ./script/Example05.s.sol:DeployBasicMessageSender -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8)" -- 2- Fund the
BasicMessageSender.solsmart contract with Native Coins, either manually using your wallet or by using thecast sendcommand. For example, if you want to send 0.1 Fuji AVAX, run:
cast send <BASIC_MESSAGE_SENDER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY --value 0.1ether- Deploy the
BasicMessageReceiver.solsmart contract to the destination blockchain. For this purpose, you can reuse thescript/Example02.s.sol:DeployBasicMessageReceiversmart contract from the second example:
function run(SupportedNetworks destination) external;For example, to deploy it to Ethereum Sepolia, run:
forge script ./script/Example02.s.sol:DeployBasicMessageReceiver -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0- Finally, send a cross-chain message using the
script/Example05.s.sol:SendMessagesmart contract:
function run(
address payable sender,
SupportedNetworks destination,
address receiver,
string memory message,
BasicMessageSender.PayFeesIn payFeesIn
) external;For example, if you want to send a "Hello World" message type:
forge script ./script/Example05.s.sol:SendMessage -vvv --broadcast --rpc-url avalancheFuji --sig "ru
n(address,uint8,address,string,uint8)" -- <BASIC_MESSAGE_SENDER_ADDRESS> 0 <BASIC_MESSAGE_RECEIVER_ADDRESS> "Hello World"
0- Once the CCIP message is finalized on the destination blockchain, you can see the details about the latest message using the
script/Example02.s.sol:GetLatestMessageDetailssmart contract:
function run(address basicMessageReceiver) external view;For example,
forge script ./script/Example02.s.sol:GetLatestMessageDetails -vvv --broadcast --rpc-url ethereumSepolia --sig "run(address)" -- <BASIC_MESSAGE_RECEIVER_ADDRESS>- You can always withdraw tokens for Chainlink CCIP fees from the
BasicMessageSender.solsmart contract using thecast sendcommand:
cast send <BASIC_MESSAGE_SENDER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY "withdraw(address)" <BENEFICIARY_ADDRESS>To send simple Text Cross-Chain Messages and pay for CCIP fees in LINK Tokens, follow the next steps:
- Deploy the
BasicMessageSender.solsmart contract on the source blockchain, using thescript/Example05.s.sol:DeployBasicMessageSendersmart contract:
function run(SupportedNetworks source) external;For example, if you want to send a simple cross-chain message from Avalanche Fuji, run:
forge script ./script/Example05.s.sol:DeployBasicMessageSender -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8)" -- 2- Fund the
BasicMessageSender.solsmart contract with Testnet LINKs, either manually using your wallet or by using thecast sendcommand. For example, if you want to send 1 Fuji LINK, run:
cast send 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 "transfer(address,uint256)" <BASIC_MESSAGE_SENDER_ADDRESS> 1000000000000000000 --rpc-url avalancheFuji --private-key=$PRIVATE_KEY- Deploy the
BasicMessageReceiver.solsmart contract to the destination blockchain. For this purpose, you can reuse thescript/Example02.s.sol:DeployBasicMessageReceiversmart contract from the second example:
function run(SupportedNetworks destination) external;For example, to deploy it to Ethereum Sepolia, run:
forge script ./script/Example02.s.sol:DeployBasicMessageReceiver -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0- Finally, send a cross-chain message using the
script/Example05.s.sol:SendMessagesmart contract:
function run(
address payable sender,
SupportedNetworks destination,
address receiver,
string memory message,
BasicMessageSender.PayFeesIn payFeesIn
) external;For example, if you want to send a "Hello World" message type:
forge script ./script/Example05.s.sol:SendMessage -vvv --broadcast --rpc-url avalancheFuji --sig "ru
n(address,uint8,address,string,uint8)" -- <BASIC_MESSAGE_SENDER_ADDRESS> 0 <BASIC_MESSAGE_RECEIVER_ADDRESS> "Hello World"
1- Once the CCIP message is finalized on the destination blockchain, you can see the details about the latest message using the
script/Example02.s.sol:GetLatestMessageDetailssmart contract:
function run(address basicMessageReceiver) external view;For example,
forge script ./script/Example02.s.sol:GetLatestMessageDetails -vvv --broadcast --rpc-url ethereumSepolia --sig "run(address)" -- <BASIC_MESSAGE_RECEIVER_ADDRESS>- You can always withdraw tokens for Chainlink CCIP fees from the
BasicMessageSender.solsmart contract using thecast sendcommand:
cast send <BASIC_MESSAGE_SENDER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY "withdrawToken(address,address)" <BENEFICIARY_ADDRESS> 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846Our goal for this example is to mint an NFT on the destination blockchain by sending the to address from the source blockchain. It is extremely simple so we can understand the basic concepts, but you can expand it to accept payment for minting on the source blockchain, add extra features, etc.
The basic architecture diagram of what we want to accomplish looks like this:
flowchart LR
subgraph "Source Blockchain"
a("SourceMinter.sol") -- "`send abi.encodeWithSignature('mint(address)', msg.sender);`" --> b("Source Router")
end
b("Source Router") --> c("CCIP")
c("CCIP") --> d("Destination Router")
subgraph "Destination Blockchain"
d("Destination Router") -- "`receive abi.encodeWithSignature('mint(address)', msg.sender);`" --> e("DestinationMinter.sol")
e("DestinationMinter.sol") -- "`call mint(to)`" --> f("MyNFT.sol")
end
- Deploy the
MyNFT.solandDestinationMinter.solsmart contracts from the./src/cross-chain-nft-minterfolder on the destination blockchain, by using thescript/CrossChainNFT.s.sol:DeployDestinationsmart contract:
function run(SupportedNetworks destination) external;For example, if you want to have an NFT collection on Ethereum Sepolia, run:
forge script ./script/CrossChainNFT.s.sol:DeployDestination -vvv --broadcast --rpc-url ethereumSepolia --sig "run(uint8)" -- 0- Deploy the
SourceMinter.solsmart contract on the source blockchain, by using thescript/CrossChainNFT.s.sol:DeploySourcesmart contract:
function run(SupportedNetworks source) external;For example, if you want to mint NFTs on Ethereum Sepolia from Avalanche Fuji, run:
forge script ./script/CrossChainNFT.s.sol:DeploySource -vvv --broadcast --rpc-url avalancheFuji --sig "run(uint8)" -- 2- Fund the
SourceMinter.solsmart contract with tokens for CCIP fees.
-
If you want to pay for CCIP fees in Native tokens:
Open Metamask and fund your contract with Native tokens. For example, if you want to mint from Avalanche Fuji to Ethereum Sepolia, you can send 0.1 Fuji AVAX to the
SourceMinter.solsmart contract.Or, you can use the
cast sendcommand:cast send <SOURCE_MINTER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY --value 0.1ether
-
If you want to pay for CCIP fees in LINK tokens:
Open Metamask and fund your contract with LINK tokens. For example, if you want to mint from Avalanche Fuji to Ethereum Sepolia, you can send 1 Fuji LINK to the
SourceMinter.solsmart contract.Or, you can use the
cast sendcommand:cast send 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 "transfer(address,uint256)" <SOURCE_MINTER_ADDRESS> 1000000000000000000 --rpc-url avalancheFuji --private-key=$PRIVATE_KEY
- Mint NFTs by calling the
mint()function of theSourceMinter.solsmart contract on the source blockchain. It will send the CCIP Cross-Chain Message with the ABI-encoded mint function signature from theMyNFT.solsmart contract. TheDestinationMinter.solsmart contracts will receive the CCIP Cross-Chain Message with the ABI-encoded mint function signature as a payload and call theMyNFT.solsmart contract using it. TheMyNFT.solsmart contract will then mint the new NFT to themsg.senderaccount from themint()function of theSourceMinter.solsmart contract, a.k.a to the account from which you will call the following command:
function run(
address payable sourceMinterAddress,
SupportedNetworks destination,
address destinationMinterAddress,
SourceMinter.PayFeesIn payFeesIn
) external;For example, if you want to mint NFTs on Ethereum Sepolia by sending requests from Avalanche Fuji, run:
forge script ./script/CrossChainNFT.s.sol:Mint -vvv --broadcast --rpc-url avalancheFuji --sig "run(a
ddress,uint8,address,uint8)" -- <SOURCE_MINTER_ADDRESS> 0 <DESTINATION_MINTER_ADDRESS> 0- Once the CCIP message is finalized on the destination blockchain, you can query the MyNFTs balance of your account, using the
cast callcommand.
For example, to verify that the new MyNFT was minted, type:
cast call <MY_NFT_ADDRESS> "balanceOf(address)" <PUT_YOUR_ADDRESS_HERE> --rpc-url ethereumSepoliaOf course, you can see your newly minted NFT on popular NFT Marketplaces, like OpenSea for instance:
- You can always withdraw tokens for Chainlink CCIP fees from the
SourceMinter.solsmart contract using thecast sendcommand.
For example, to withdraw tokens previously sent for Chainlink CCIP fees, run:
cast send <SOURCE_MINTER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY "withdraw(address)" <BENEFICIARY_ADDRESS>or
cast send <SOURCE_MINTER_ADDRESS> --rpc-url avalancheFuji --private-key=$PRIVATE_KEY "withdrawToken(address,address)" <BENEFICIARY_ADDRESS> 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846depending on whether you filled the SourceMinter.sol contract with Native (0) or LINK (1) in step number 3.


