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.
Verify installation by typing:
node -v
and
npm -v
- Install packages
npm install
- Compile contracts
npx hardhat compile
- Run tests
TS_TRANSPILE_NODE=1 npx hardhat test
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.
We are going to use the @chainlink/env-enc
package for extra security. It encrypts sensitive data instead of storing them as plain text in the .env
file, by creating a new, .env.enc
file. Although it's not recommended to push this file online, if that accidentally happens your secrets will still be encrypted.
- Set a password for encrypting and decrypting the environment variable file. You can change it later by typing the same command.
npx env-enc set-pw
- Now set the following environment variables:
PRIVATE_KEY
, Source Blockchain RPC URL, Destination Blockchain RPC URL. You can see available options in the.env.example
file:
ETHEREUM_SEPOLIA_RPC_URL=""
OPTIMISM_GOERLI_RPC_URL=""
ARBITRUM_TESTNET_RPC_URL=""
AVALANCHE_FUJI_RPC_URL=""
POLYGON_MUMBAI_RPC_URL=""
To set these variables, type the following command and follow the instructions in the terminal:
npx env-enc set
After you are done, the .env.enc
file will be automatically generated.
If you want to validate your inputs you can always run the next command:
npx env-enc view
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 faucet
task. 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
.
npx hardhat faucet
--receiver <RECEIVER_ADDRESS>
--ccip-bnm <CCIP_BnM_ADDRESS> # Optional
--ccip-lnm <CCIP_LnM_ADDRESS> # Optional
For example, to mint tokens on ethereumSepolia run:
npx hardhat faucet --network ethereumSepolia --receiver <RECEIVER_ADDRESS>
To transfer tokens from one EOA on one blockchain to another EOA on another blockchain you can use the ccip-token-transfer
command:
npx hardhat ccip-token-transfer
--source-blockchain <sourceBlockchain>
--destination-blockchain <destinationBlockchain>
--receiver <receiverAddressOnDestinationBlockchain>
--token-address <tokenToSendAddressOnSourceBlockchain>
--amount <amountToSend>
--fee-token-address <feeTokenAddress> # Optional
--router <sourceChainRouterAddress> # Optional
--gasLimit <gasLimit> # Optional
Where the list of supported chains consists of (case sensitive):
- ethereumSepolia
- optimismGoerli
- arbitrumTestnet
- avalancheFuji
- polygonMumbai
For example, if you want to send 100 units of Sepolia test LINK token from Ethereum Sepolia to Avalanche Fuji, and you want to pay for CCIP fees in native coin (Sepolia ether in this case), run:
npx hardhat ccip-token-transfer --source-blockchain ethereumSepolia --destination-blockchain avalancheFuji --receiver <RECEIVER_ADDRESS> --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 100 --gas-limit 0
If you want to pay for CCIP fees in Sepolia test LINK, expand the previous command with the additional --fee-token-address
flag:
npx hardhat ccip-token-transfer --source-blockchain ethereumSepolia --destination-blockchain avalancheFuji --receiver <RECEIVER_ADDRESS> --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 100 --gas-limit 0 --fee-token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789
The proposed CCIP best practice is to always verify the Router.sol
address. If you want to pass the source blockchain Router.sol
address you can use the optional --router
flag:
npx hardhat ccip-token-transfer --source-blockchain ethereumSepolia --destination-blockchain avalancheFuji --receiver <RECEIVER_ADDRESS> --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 100 --gas-limit 0 --fee-token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789 --router <ROUTER_ADDRESS>
To transfer tokens from EOA from the source blockchain to the smart contract on the destination blockchain, follow the next steps:
- Deploy
BasicMessageReceiver.sol
to the destination blockchain, using thedeploy-basic-message-receiver
task:
npx hardhat deploy-basic-message-receiver
--router <routerAddress> # Optional
For example, if you want to send tokens from ethereumSepolia to avalancheFuji, you need to deploy this contract on avalancheFuji, by running:
npx hardhat deploy-basic-message-receiver --network avalancheFuji
Optionally, you can pass the address of the Chainlink CCIP Router.sol
smart contract on the avalancheFuji blockchain as a constructor argument. To do so, run the following command:
npx hardhat deploy-basic-message-receiver --network avalancheFuji --router <ROUTER_ADDRESS>
- Transfer tokens to the deployed smart contract using the
ccip-token-transfer
task, by putting its address as a receiver flag. For example, if you want to send 100 units of LINK from ethereumSepolia run:
npx hardhat ccip-token-transfer --source-blockchain ethereumSepolia --destination-blockchain avalancheFuji --receiver <BASIC_MESSAGE_RECEIVER_ADDRESS> --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 100
- Once the CCIP message is finalized on the destination blockchain, you can always withdraw received tokens from the
BasicMessageReceiver.sol
smart contract using thewithdraw
task. Note that the--token-address
flag is optional. If not provided, native coins will be withdrawn.
npx hardhat withdraw
--beneficiary <withdrawTo>
--blockchain <basicMessageReceiverBlockchain>
--from <basicMessageReceiverAddress>
--token-address <tokenToWithdraw> # Optional, if left empty native coins will be withdrawn
For example, to withdraw 100 units of LINK previously sent, run:
npx hardhat withdraw --beneficiary <BENEFICIARY_ADDRESS> --blockchain avalancheFuji --from <BASIC_MESSAGE_RECEIVER_ADDRESS> --token-address 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846
To 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.sol
to the source blockchain, using thedeploy-basic-token-sender
task:
npx hardhat deploy-basic-token-sender
--router <routerAddress> # Optional
--link <linkTokenAddress> # Optional
For example, if you want to send tokens from ethereumSepolia to avalancheFuji, run:
npx hardhat deploy-basic-token-sender --network ethereumSepolia
- [OPTIONAL] If you want to send tokens to the smart contract, instead of EOA, you will need to deploy
BasicMessageReceiver.sol
to the destination blockchain, using thedeploy-basic-message-receiver
task, and then put the address of that smart contract as a receiver.
For example, if you want to send tokens from the BasicTokenSender.sol
smart contract on the ethereumSepolia blockchain to the BasicMessageReceiver.sol
smart contract on the avalancheFuji blockchain, run:
npx hardhat deploy-basic-message-receiver --network avalancheFuji
- Fill the
BasicTokenSender.sol
with tokens/coins for fees (you can always withdraw it later). You can do it manually from your wallet or by running the following task:
npx hardhat fill-sender
--sender-address <addressOfBasicTokenSenderContractWeDeployed>
--blockchain <blockchain>
--amount <amountToSend>
--pay-fees-in <Native | LINK>
For example, if you want to send tokens from ethereumSepolia and fund it with 0.1 Sepolia ether for Chainlink CCIP fees, run:
npx hardhat fill-sender --sender-address <BASIC_TOKEN_SENDER_ADDRESS> --blockchain ethereumSepolia --amount 10000000000000000 --pay-fees-in Native
- Finally, send tokens by providing the array of
{token, amount}
objects, using theccip-token-transfer-batch
task:
npx hardhat ccip-token-transfer-batch
--source-blockchain <sourceBlockchain>
--basic-token-sender-address <addressOfBasicTokenSenderContractWeDeployed>
--destination-blockchain <destinationBlockchain>
--receiver <receiverAddressOnDestinationBlockchain>
--token-amounts <tokenAmounts>
--pay-fees-in <Native | LINK>
--router <router> # Optional
The payFeesIn
flag determines whether you are paying for CCIP fees with LINK tokens or native coins on the source blockchain (Pass "Native" or "LINK").
For example, to send 100 units of LINK tokens and 100 units of CCIP-BnM tokens from ethereumSepolia to avalancheFuji and pay fees in Sepolia ether, run:
npx hardhat ccip-token-transfer-batch --source-blockchain ethereumSepolia --basic-token-sender-address <BASIC_TOKEN_SENDER_ADDRESS> --destination-blockchain avalancheFuji --receiver <RECEIVER_ADDRESS> --token-amounts '[{"token":"0x779877A7B0D9E8603169DdbD7836e478b4624789","amount":"100"},{"token":"0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05","amount":"100"}]' --pay-fees-in Native
- You can always withdraw tokens for Chainlink CCIP fees from the
BasicTokenSender.sol
smart contract using thewithdraw
task. Note that the--token-address
flag is optional. If not provided, native coins will be withdrawn.
npx hardhat withdraw
--beneficiary <withdrawTo>
--blockchain <basicTokenSenderBlockchain>
--from <basicTokenSenderAddress>
--token-address <tokensToWithdraw> # Optional, if left empty native coins will be withdrawn
For example, to withdraw Sepolia ether previously sent for Chainlink CCIP fees, run:
npx hardhat withdraw --beneficiary <BENEFICIARY_ADDRESS> --blockchain ethereumSepolia --from <BASIC_TOKEN_SENDER_ADDRESS>
To transfer tokens and data across multiple chains, follow the next steps:
- Deploy the
ProgrammableTokenTransfers.sol
smart contract to the source blockchain, using thedeploy-programmable-token-transfers
task:
npx hardhat deploy-programmable-token-transfers
--router <router> # Optional
For example, if you want to send a message from Ethereum Sepolia to Polygon Mumbai type:
npx hardhat deploy-programmable-token-transfers --network ethereumSepolia
-
Open Metamask and fund your contract with Native tokens. For example, if you want to send a message from Ethereum Sepolia to Polygon Mumbai, you can send 0.1 Sepolia ETH to your contract.
-
Open Metamask and fund your contract with LINK tokens. For example, if you want to send a message from Ethereum Sepolia to Polygon Mumbai, you can send 0.01 Sepolia LINK to your contract.
-
Deploy the
ProgrammableTokenTransfers.sol
smart contract to the destination blockchain:
For example, if you want to receive a message from Ethereum Sepolia on Polygon Mumbai type:
npx hardhat deploy-programmable-token-transfers --network polygonMumbai
At 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, by running:
npx hardhat send-token-and-data
--source-blockchain <sourceBlockchain>
--sender <addressOfProgrammableTokenTransfersOnSourceBlockchain>
--destination-blockchain <destinationBlockchain>
--receiver <ddressOfProgrammableTokenTransfersOnDestinationBlockchain>
--message <messageToSend>
--token-address <tokenToSendAddressOnSourceBlockchain>
--amount <amountToSend>
--router <router> # Optional
For example, if you want to send a "Hello World" message alongside 100 Sepolia LINK from Ethereum Sepolia to Polygon Mumbai type:
npx hardhat send-token-and-data --source-blockchain ethereumSepolia --sender <CONTRACT_ADDRESS_ON_SOURCE_BLOCKCHAIN> --destination-blockchain polygonMumbai --receiver <CONTRACT_ADDRESS_ON_DESTINATION_BLOCKCHAIN> --message "Hello World" --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 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
get-received-message-details
task:
npx hardhat get-received-message-details
--blockchain <destinationBlockchain>
--contract-address <programmableTokenTransfersAddressOnDestinationBlockchain>
For example,
npx hardhat get-received-message-details --blockchain ethereumSepolia --contract-address <PROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS_ON_DESTINATION_BLOCKCHAIN>
To send simple Text Cross-Chain Messages and pay for CCIP fees in Native Tokens, follow the next steps:
- Deploy the
BasicMessageSender.sol
smart contract on the source blockchain, using thedeploy-basic-message-sender
task:
npx hardhat deploy-basic-message-sender
--router <routerAddress> # Optional
--link <linkTokenAddress> # Optional
For example, if you want to send a simple cross-chain message from ethereumSepolia, run
npx hardhat deploy-basic-message-sender --network ethereumSepolia
- Fund the
BasicMessageSender.sol
smart contract with Native Coins, either manually using your wallet or by using thefill-sender
task.
For example, if you want to send 0.01 Sepolia ether, run:
npx hardhat fill-sender --sender-address <BASIC_MESSAGE_SENDER_ADDRESS> --blockchain ethereumSepolia --amount 10000000000000000 --pay-fees-in Native
- Deploy the
BasicMessageReceiver.sol
smart contract to the destination blockchain, using thedeploy-basic-message-receiver
task.
For example, if you want to receive a simple cross-chain message on the avalancheFuji blockchain, run:
npx hardhat deploy-basic-message-receiver --network avalancheFuji
- Finally, send a cross-chain message using the
send-message
task:
npx hardhat send-message
--source-blockchain <sourceBlockchain>
--sender <addressOfBasicMessageSenderOnSourceBlockchain>
--destination-blockchain <destinationBlockchain>
--receiver <ddressOfBasicMessageReceiverOnDestinationBlockchain>
--message <messageToSend>
--pay-fees-in <Native>
For example, if you want to send a "Hello, World!" message type:
npx hardhat send-message --source-blockchain ethereumSepolia --sender <BASIC_MESSAGE_SENDER_ADDRESS> --destination-blockchain avalancheFuji --receiver <BASIC_MESSAGE_RECEIVER_ADDRESS> --message 'Hello, World!' --pay-fees-in Native
- Once the CCIP message is finalized on the destination blockchain, you can query the latest received message details, using the
get-message
task:
npx hardhat get-message
--blockchain <destinationBlockchain>
--receiver-address <basicMessageReceiverAddress>
For example, to get the message details sent in the previous step, type:
npx hardhat get-message --blockchain avalancheFuji --receiver-address <BASIC_MESSAGE_RECEIVER_ADDRESS>
- You can always withdraw tokens for Chainlink CCIP fees from the
BasicMessageSender.sol
smart contract using thewithdraw
task. Note that the--token-address
flag is optional. If not provided, native coins will be withdrawn.
npx hardhat withdraw
--beneficiary <withdrawTo>
--blockchain <basicMessageSenderBlockchain>
--from <basicMessageSenderAddress>
--token-address <tokensToWithdraw> # Optional, if left empty native coins will be withdrawn
For example, to withdraw Sepolia ether previously sent for Chainlink CCIP fees, run:
npx hardhat withdraw --beneficiary <BENEFICIARY_ADDRESS> --blockchain ethereumSepolia --from <BASIC_MESSAGE_SENDER_ADDRESS>
To send simple Text Cross-Chain Messages and pay for CCIP fees in LINK Tokens, follow the next steps:
- Deploy the
BasicMessageSender.sol
smart contract on the source blockchain, using thedeploy-basic-message-sender
task:
npx hardhat deploy-basic-message-sender
--router <routerAddress> # Optional
--link <linkTokenAddress> # Optional
For example, if you want to send a simple cross-chain message from ethereumSepolia, run
npx hardhat deploy-basic-message-sender --network ethereumSepolia
- Fund the
BasicMessageSender.sol
smart contract with Testnet LINKs, either manually using your wallet or by using thefill-sender
task.
For example, if you want to send 0.001 Sepolia LINK, run:
npx hardhat fill-sender --sender-address <BASIC_MESSAGE_SENDER_ADDRESS> --blockchain ethereumSepolia --amount 1000000000000000 --pay-fees-in LINK
- Deploy the
BasicMessageReceiver.sol
smart contract to the destination blockchain, using thedeploy-basic-message-receiver
task.
For example, if you want to receive a simple cross-chain message on the avalancheFuji blockchain, run:
npx hardhat deploy-basic-message-receiver --network avalancheFuji
- Finally, send a cross-chain message using the
send-message
task:
npx hardhat send-message
--source-blockchain <sourceBlockchain>
--sender <addressOfBasicMessageSenderOnSourceBlockchain>
--destination-blockchain <destinationBlockchain>
--receiver <ddressOfBasicMessageReceiverOnDestinationBlockchain>
--message <messageToSend>
--pay-fees-in <LINK>
For example, if you want to send a "Hello, World!" message type:
npx hardhat send-message --source-blockchain ethereumSepolia --sender <BASIC_MESSAGE_SENDER_ADDRESS> --destination-blockchain avalancheFuji --receiver <BASIC_MESSAGE_RECEIVER_ADDRESS> --message 'Hello, World!' --pay-fees-in LINK
- Once the CCIP message is finalized on the destination blockchain, you can query the latest received message details, using the
get-message
task:
npx hardhat get-message
--blockchain <destinationBlockchain>
--receiver-address <basicMessageReceiverAddress>
For example, to get the message details sent in the previous step, type:
npx hardhat get-message --blockchain avalancheFuji --receiver-address <BASIC_MESSAGE_RECEIVER_ADDRESS>
- You can always withdraw tokens for Chainlink CCIP fees from the
BasicMessageSender.sol
smart contract using thewithdraw
task. Note that the--token-address
flag is optional. If not provided, native coins will be withdrawn.
npx hardhat withdraw
--beneficiary <withdrawTo>
--blockchain <basicMessageSenderBlockchain>
--from <basicMessageSenderAddress>
--token-address <tokensToWithdraw> # Optional, if left empty native coins will be withdrawn
For example, to withdraw Sepolia LINK previously sent for Chainlink CCIP fees, run:
npx hardhat withdraw --beneficiary <BENEFICIARY_ADDRESS> --blockchain ethereumSepolia --from <BASIC_MESSAGE_SENDER_ADDRESS> --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789
Our 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, grant minter role to CCIP receiver contract on the destination blockchain, 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.sol
andDestinationMinter.sol
smart contracts from the./contracts/cross-chain-nft-minter
folder on the destination blockchain, by running thedeploy-destination-cross-chain-nft-minter
task:
npx hardhat deploy-destination-cross-chain-nft-minter
--router <routerAddress> # Optional
For example, if you want to mint NFTs on avalancheFuji, run:
npx hardhat deploy-destination-cross-chain-nft-minter --network avalancheFuji
- Deploy the
SourceMinter.sol
smart contract on the source blockchain, by running thedeploy-source-cross-chain-nft-minter
task:
npx hardhat deploy-source-cross-chain-nft-minter
--router <routerAddress> # Optional
--link <linkTokenAddress> # Optional
For example, if you want to mint NFTs on avalancheFuji by sending requests from ethereumSepolia, run:
npx hardhat deploy-source-cross-chain-nft-minter --network ethereumSepolia
- Fund the
SourceMinter.sol
smart 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 Ethereum Sepolia to Avalanche Fuji, you can send 0.01 Sepolia ETH to the
SourceMinter.sol
smart contract.Or, you can execute the
fill-sender
task, by running:
npx hardhat fill-sender
--sender-address <sourceMinterAddress>
--blockchain <blockchain>
--amount <amountToSend>
--pay-fees-in <Native>
For example, if you want to fund it with 0.01 Sepolia ETH, run:
npx hardhat fill-sender --sender-address <SOURCE_MINTER_ADDRESS> --blockchain ethereumSepolia --amount 10000000000000000 --pay-fees-in Native
-
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 Ethereum Sepolia to Avalanche Fuji, you can send 0.001 Sepolia LINK to the
SourceMinter.sol
smart contract.Or, you can execute the
fill-sender
task, by running:
npx hardhat fill-sender
--sender-address <sourceMinterAddress>
--blockchain <blockchain>
--amount <amountToSend>
--pay-fees-in <LINK>
For example, if you want to fund it with 0.001 Sepolia LINK, run:
npx hardhat fill-sender --sender-address <SOURCE_MINTER_ADDRESS> --blockchain ethereumSepolia --amount 1000000000000000 --pay-fees-in LINK
- Mint NFTs by calling the
mint()
function of theSourceMinter.sol
smart contract on the source blockchain. It will send the CCIP Cross-Chain Message with the ABI-encoded mint function signature from theMyNFT.sol
smart contract. TheDestinationMinter.sol
smart contracts will receive the CCIP Cross-Chain Message with the ABI-encoded mint function signature as a payload and call theMyNFT.sol
smart contract using it. TheMyNFT.sol
smart contract will then mint the new NFT to themsg.sender
account from themint()
function of theSourceMinter.sol
smart contract, a.k.a to the account from which you will call the following command:
npx hardhat cross-chain-mint
--source-minter <sourceMinterAddress>
--source-blockchain <sourceBlockchain>
--destination-blockchain <destinationBlockchain>
--destination-minter <destinationMinterAddress>
--pay-fees-in <Native | LINK>
For example, if you want to mint NFTs on Avalanche Fuji by sending requests from Ethereum Sepolia, run:
npx hardhat cross-chain-mint --source-minter <SOURCE_MINTER_ADDRESS> --source-blockchain ethereumSepolia --destination-blockchain avalancheFuji --destination-minter <DESTNATION_MINTER_ADDRESS> --pay-fees-in Native
- Once the CCIP message is finalized on the destination blockchain, you can query the MyNFTs balance of your account, using the
cross-chain-mint-balance-of
task:
npx hardhat cross-chain-mint-balance-of
--my-nft <myNftContractAddress>
--blockchain <destinationBlockchain>
--owner <theAccountToCheckBalanceOf>
For example, to verify that the new MyNFT was minted, type:
npx hardhat cross-chain-mint-balance-of --my-nft <MY_NFT_CONTRACT_ADDRESS> --blockchain avalancheFuji --owner <PUT_YOUR_EOA_ADDRESS_HERE>
Of 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.sol
smart contract using thewithdraw
task. Note that the--token-address
flag is optional. If not provided, native coins will be withdrawn.
npx hardhat withdraw
--beneficiary <withdrawTo>
--blockchain <sourceMinterBlockchain>
--from <sourceMinterAddress>
--token-address <tokensToWithdraw> # Optional, if left empty native coins will be withdrawn
For example, to withdraw tokens previously sent for Chainlink CCIP fees, run:
npx hardhat withdraw --beneficiary <BENEFICIARY_ADDRESS> --blockchain ethereumSepolia --from <SOURCE_MINTER_ADDRESS>
or
npx hardhat withdraw --beneficiary <BENEFICIARY_ADDRESS> --blockchain ethereumSepolia --from <SOURCE_MINTER_ADDRESS> --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789
depending on whether you filled the SourceMinter.sol
contract with Native
or LINK
in step number 3.