{"id":19107340,"url":"https://github.com/smartcontractkit/ccip-starter-kit-hardhat","last_synced_at":"2025-04-05T17:04:08.606Z","repository":{"id":182284206,"uuid":"661785542","full_name":"smartcontractkit/ccip-starter-kit-hardhat","owner":"smartcontractkit","description":"This project demonstrates a couple of basic Chainlink CCIP use cases","archived":false,"fork":false,"pushed_at":"2025-02-04T07:52:23.000Z","size":2116,"stargazers_count":66,"open_issues_count":5,"forks_count":53,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-29T16:07:26.986Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smartcontractkit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-03T16:34:49.000Z","updated_at":"2025-03-17T23:27:54.000Z","dependencies_parsed_at":"2024-01-17T09:33:37.522Z","dependency_job_id":"660603dc-d7b5-4a81-8681-a6bb1d0a887d","html_url":"https://github.com/smartcontractkit/ccip-starter-kit-hardhat","commit_stats":{"total_commits":26,"total_committers":9,"mean_commits":2.888888888888889,"dds":0.5384615384615384,"last_synced_commit":"3bbe51ecf486970e13319005faba0d64fb201408"},"previous_names":["smartcontractkit/ccip-starter-kit-hardhat"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smartcontractkit%2Fccip-starter-kit-hardhat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smartcontractkit%2Fccip-starter-kit-hardhat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smartcontractkit%2Fccip-starter-kit-hardhat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smartcontractkit%2Fccip-starter-kit-hardhat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smartcontractkit","download_url":"https://codeload.github.com/smartcontractkit/ccip-starter-kit-hardhat/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247369953,"owners_count":20927928,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T04:12:13.435Z","updated_at":"2025-04-05T17:04:08.581Z","avatar_url":"https://github.com/smartcontractkit.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## CCIP Starter Kit\n\n\u003e **Note**\n\u003e\n\u003e _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._\n\nThis project demonstrates a couple of basic Chainlink CCIP use cases.\n\n## Table of Contents\n\n- [Prerequisites](#prerequisites)\n- [Getting Started](#getting-started)\n  - [Install packages](#install-packages)\n  - [Compile contracts](#compile-contracts)\n- [What is Chainlink CCIP?](#what-is-chainlink-ccip)\n- [Usage](#usage)\n  - [Set a password for encrypting and decrypting the environment variable file](#set-a-password-for-encrypting-and-decrypting-the-environment-variable-file)\n  - [Set environment variables](#set-environment-variables)\n  - [Validate your inputs](#validate-your-inputs)\n- [Tests](#tests)\n  - [No Fork](#no-fork)\n  - [Fork](#fork)\n  - [Faucet](#faucet)\n- [Example 1 - Transfer CCIP Test Tokens from EOA to EOA](#example-1---transfer-ccip-test-tokens-from-eoa-to-eoa)\n- [Example 2 - Transfer Tokens from EOA to Smart Contract](#example-2---transfer-tokens-from-eoa-to-smart-contract)\n- [Example 3 - Transfer Token(s) from Smart Contract to any destination](#example-3---transfer-tokens-from-smart-contract-to-any-destination)\n- [Example 4 - Send \u0026 Receive Tokens and Data](#example-4---send--receive-tokens-and-data)\n- [Example 5 - Send \u0026 Receive Cross-Chain Messages and Pay with Native Coins](#example-5---send--receive-cross-chain-messages-and-pay-with-native-coins)\n- [Example 6 - Send \u0026 Receive Cross-Chain Messages and Pay with LINK Tokens](#example-6---send--receive-cross-chain-messages-and-pay-with-link-tokens)\n- [Example 7 - Execute Received Message as a Function Call](#example-7---execute-received-message-as-a-function-call)\n\n## Prerequisites\n\n- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)\n- [Current LTS Node.js version](https://nodejs.org/en/about/releases/)\n\nVerify installation by typing:\n\n```shell\nnode -v\n```\n\nand\n\n```shell\nnpm -v\n```\n\n## Getting Started\n\n1. Install packages\n\n```\nnpm install\n```\n\n2. Compile contracts\n\n```\nnpm run compile\n```\n\n## What is Chainlink CCIP?\n\n**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.\n\n![basic-architecture](./img/basic-architecture.png)\n\nWith Chainlink CCIP, one can:\n\n- Transfer supported tokens\n- Send messages (any data)\n- Send messages and tokens\n\nCCIP receiver can be:\n\n- Smart contract that implements `CCIPReceiver.sol`\n- EOA\n\n**Note**: If you send a message and token(s) to EOA, only tokens will arrive\n\nTo 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](https://docs.chain.link/ccip).\n\n## Usage\n\nIn 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.\n\nWe are going to use the [`@chainlink/env-enc`](https://www.npmjs.com/package/@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.\n\n1. Set a password for encrypting and decrypting the environment variable file. You can change it later by typing the same command.\n\n```shell\nnpx env-enc set-pw\n```\n\n2. 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 or check out the [latest supported networks in the docs](https://docs.chain.link/ccip/supported-networks):\n\n```shell\nETHEREUM_SEPOLIA_RPC_URL=\"\"\nOPTIMISM_SEPOLIA_RPC_URL=\"\"\nARBITRUM_SEPOLIA_RPC_URL=\"\"\nAVALANCHE_FUJI_RPC_URL=\"\"\nPOLYGON_AMOY_RPC_URL=\"\"\nBNB_CHAIN_TESTNET_RPC_URL=\"\"\nBASE_SEPOLIA_RPC_URL=\"\"\nKROMA_SEPOLIA_RPC_URL=\"\"\nWEMIX_TESTNET_RPC_URL=\"\"\nGNOSIS_CHIADO_RPC_URL=\"\"\nCELO_ALFAJORES_RPC_URL=\"\"\nMETIS_SEPOLIA_RPC_URL=\"\"\nZKSYNC_SEPOLIA_RPC_URL=\"\"\nSCROLL_SEPOLIA_RPC_URL=\"\"\nZIRCUIT_SEPOLIA_RPC_URL=\"\"\nXLAYER_SEPOLIA_RPC_URL=\"\"\nPOLYGON_ZKEVM_SEPOLIA_RPC_URL=\"\"\nPOLKADOT_ASTAR_SHIBUYA_RPC_URL=\"\"\nMANTLE_SEPOLIA_RPC_URL=\"\"\nSONEIUM_MINATO_SEPOLIA_RPC_URL=\"\"\nBSQUARED_TESTNET_RPC_URL=\"\"\nBOB_SEPOLIA_RPC_URL=\"\"\nWORLDCHAIN_SEPOLIA_RPC_URL=\"\"\nSHIBARIUM_TESTNET_RPC_URL=\"\"\nBITLAYER_TESTNET_RPC_URL=\"\"\nFANTOM_SONIC_TESTNET_RPC_URL=\"\"\nCORN_TESTNET_RPC_URL=\"\"\nHASHKEY_SEPOLIA_RPC_URL=\"\"\nINK_SEPOLIA_RPC_URL=\"\"\n```\n\nTo set these variables, type the following command and follow the instructions in the terminal:\n\n```shell\nnpx env-enc set\n```\n\nAfter you are done, the `.env.enc` file will be automatically generated.\n\nIf you want to validate your inputs you can always run the next command:\n\n```shell\nnpx env-enc view\n```\n\n## Tests\n\nThere are two types of tests in this project:\n\n- **./test/no-fork/**: These tests run on your local hardhat node and do not require forking.\n- **./test/fork/**: These tests run on a forked mainnet network and require forking the source and destination blockchains.\n\n\u003e **Note**  \n\u003e Tests in the test folder have names like Example1.spec.ts, where `Example1` maps to the [#example-1](#example-1---transfer-ccip-test-tokens-from-eoa-to-eoa) scenario below.\n\n### No Fork\n\nTo run the tests that do not require forking, type:\n\n```shell\nnpm run test:no-fork\n```\n\n### Fork\n\nThe tests are forking _Arbitrum Sepolia_ as source chain and _Ethereum Sepolia_ as destination chain. Before you begin, make sure to set up the rpc urls in your `.env.enc` file.\n\nTo run the tests that require forking, type:\n\n```shell\nnpm run test:fork\n```\n\n### Faucet\n\nYou 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 ERC20 tokens (`CCIP-BnM` and `CCIP-LnM`) that you can mint permissionlessly on each supported testnet so you don't run out of tokens while testing different scenarios. You can get the addresses for the test tokens, for each supported network, [here](https://docs.chain.link/ccip/supported-networks). You can understand the architecture principles behind these two test tokens [here](https://docs.chain.link/ccip/architecture#token-pools).\n\nTo 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`.\n\n```shell\nnpx hardhat faucet\n--receiver \u003cRECEIVER_ADDRESS\u003e\n--ccip-bnm \u003cCCIP_BnM_ADDRESS\u003e # Optional\n--ccip-lnm \u003cCCIP_LnM_ADDRESS\u003e # Optional\n```\n\nFor example, to mint tokens on ethereumSepolia run:\n\n```shell\nnpx hardhat faucet --network ethereumSepolia --receiver \u003cRECEIVER_ADDRESS\u003e\n```\n\n### Example 1 - Transfer CCIP Test Tokens from EOA to EOA\n\nTo transfer tokens from one EOA on one blockchain to another EOA on another blockchain you can use the `ccip-token-transfer` command:\n\n```shell\nnpx hardhat ccip-token-transfer\n--source-blockchain \u003csourceBlockchain\u003e\n--destination-blockchain \u003cdestinationBlockchain\u003e\n--receiver \u003creceiverAddressOnDestinationBlockchain\u003e\n--token-address \u003ctokenToSendAddressOnSourceBlockchain\u003e\n--amount \u003camountToSend\u003e     # in units (eg wei)\n--fee-token-address  \u003cfeeTokenAddress\u003e # Optional\n--router \u003csourceChainRouterAddress\u003e # Optional\n--gasLimit \u003cgasLimit\u003e # Optional\n```\n\nWhere the list of supported chains consists of (case sensitive):\n\n- ethereumSepolia\n- polygonAmoy\n- optimismSepolia\n- arbitrumSepolia\n- avalancheFuji\n- bnbChainTestnet\n- baseSepolia\n- kromaSepolia\n- wemixTestnet\n- gnosisChiado\n- celoAlfajores\n- metisSepolia\n- zksyncSepolia\n- scrollSepolia\n- zircuitSepolia\n- xlayerSepolia\n- polygonZkevmSepolia\n- polkadotAstarShibuya\n- mantleSepolia\n- soneiumMinatoSepolia\n- bsquaredTestnet\n- bobSepolia\n- worldchainSepolia\n- shibariumTestnet\n- bitlayerTestnet\n- fantomSonicTestnet\n- cornTestnet\n- hashkeySepolia\n- inkSepolia\n\nFor example, if you want to send 100 units of CCIP-BnM token from Avalanche Fuji to Ethereum Sepolia, and you want to pay for CCIP fees in native coin (Avalanche Fuji AVAX in this case), run:\n\n```shell\nnpx hardhat ccip-token-transfer --source-blockchain avalancheFuji --destination-blockchain ethereumSepolia --receiver \u003cRECEIVER_ADDRESS\u003e --token-address 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 --amount 100 --gas-limit 0\n```\n\nIf you want to pay for CCIP fees in Avalanche Fuji test LINK, expand the previous command with the additional `--fee-token-address` flag:\n\n```shell\nnpx hardhat ccip-token-transfer --source-blockchain avalancheFuji --destination-blockchain ethereumSepolia --receiver \u003cRECEIVER_ADDRESS\u003e --token-address 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 --amount 100 --gas-limit 0 --fee-token-address 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846\n```\n\nThe 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:\n\n```shell\nnpx hardhat ccip-token-transfer --source-blockchain avalancheFuji --destination-blockchain ethereumSepolia --receiver \u003cRECEIVER_ADDRESS\u003e --token-address 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 --amount 100 --gas-limit 0 --fee-token-address 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846 --router \u003cROUTER_ADDRESS\u003e\n```\n\n\u003e ⚠️ **Note:** The gas limit is set to 0 because the transaction is directed to an Externally Owned Account (EOA). Gas limits on destination chains are needed only when sending data or tokens to a smart contract.\n\n### Example 2 - Transfer Tokens from EOA to Smart Contract\n\nTo transfer tokens from EOA from the source blockchain to the smart contract on the destination blockchain, follow the next steps:\n\n1. Deploy [`BasicMessageReceiver.sol`](./contracts/BasicMessageReceiver.sol) to the **destination blockchain**, using the `deploy-basic-message-receiver` task:\n\n```shell\nnpx hardhat deploy-basic-message-receiver\n--router \u003crouterAddress\u003e # Optional\n```\n\nFor example, if you want to send tokens from Avalanche Fuji to Ethereum Sepolia, you need to deploy this contract on Ethereum Sepolia, by running:\n\n```shell\nnpx hardhat deploy-basic-message-receiver --network ethereumSepolia\n```\n\nOptionally, you can pass the address of the Chainlink CCIP `Router.sol` smart contract on the Ethereum Sepolia blockchain as a constructor argument. To do so, run the following command:\n\n```shell\nnpx hardhat deploy-basic-message-receiver --network ethereumSepolia --router \u003cROUTER_ADDRESS\u003e\n```\n\n2. 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 CCIP-BnM from Avalanche Fuji run:\n\n```shell\nnpx hardhat ccip-token-transfer --source-blockchain avalancheFuji --destination-blockchain ethereumSepolia --receiver \u003cBASIC_MESSAGE_RECEIVER_ADDRESS\u003e --token-address 0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4 --amount 100 --fee-token-address 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846\n```\n\n3. Once the CCIP message is finalized on the destination blockchain, you can always withdraw received tokens from the [`BasicMessageReceiver.sol`](./contracts/BasicMessageReceiver.sol) smart contract using the `withdraw` task. Note that the `--token-address` flag is optional. If not provided, native coins will be withdrawn.\n\n```shell\nnpx hardhat withdraw\n--beneficiary \u003cwithdrawTo\u003e\n--blockchain \u003cbasicMessageReceiverBlockchain\u003e\n--from \u003cbasicMessageReceiverAddress\u003e\n--token-address \u003ctokenToWithdraw\u003e # Optional, if left empty native coins will be withdrawn\n```\n\nFor example, to withdraw 100 units of CCIP-BnM previously sent, run:\n\n```shell\nnpx hardhat withdraw --beneficiary \u003cBENEFICIARY_ADDRESS\u003e --blockchain ethereumSepolia --from \u003cBASIC_MESSAGE_RECEIVER_ADDRESS\u003e --token-address 0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05\n```\n\n### Example 3 - Transfer Token(s) from Smart Contract to any destination\n\nTo transfer a token or batch of tokens from a single, universal, smart contract to any address on the destination blockchain follow the next steps:\n\n1. Deploy [`BasicTokenSender.sol`](./contracts/BasicTokenSender.sol) to the **source blockchain**, using the `deploy-basic-token-sender` task:\n\n```shell\nnpx hardhat deploy-basic-token-sender\n--router \u003crouterAddress\u003e # Optional\n--link \u003clinkTokenAddress\u003e # Optional\n```\n\nFor example, if you want to send tokens from avalancheFuji to ethereumSepolia, run:\n\n```shell\nnpx hardhat deploy-basic-token-sender --network avalancheFuji\n```\n\n2. [OPTIONAL] If you want to send tokens to the smart contract, instead of EOA, you will need to deploy [`BasicMessageReceiver.sol`](./contracts/BasicMessageReceiver.sol) to the **destination blockchain**, using the `deploy-basic-message-receiver` task, and then put the address of that smart contract as a receiver.\n\nFor example, if you want to send tokens from the [`BasicTokenSender.sol`](./contracts/BasicTokenSender.sol) smart contract on the Avalanche Fuji blockchain to the [`BasicMessageReceiver.sol`](./contracts/BasicMessageReceiver.sol) smart contract on the Ethereum Sepolia blockchain, run:\n\n```shell\nnpx hardhat deploy-basic-message-receiver --network ethereumSepolia\n```\n\n3. Fill the [`BasicTokenSender.sol`](./contracts/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:\n\n```shell\nnpx hardhat fill-sender\n--sender-address \u003caddressOfBasicTokenSenderContractWeDeployed\u003e\n--blockchain \u003cblockchain\u003e\n--amount \u003camountToSend\u003e\n--pay-fees-in \u003cNative | LINK\u003e\n```\n\nFor example, if you want to send tokens from Avalanche Fuji and fund it with 3 Avalanche Fuji LINK for Chainlink CCIP fees, run:\n\n```shell\nnpx hardhat fill-sender --sender-address \u003cBASIC_TOKEN_SENDER_ADDRESS\u003e --blockchain avalancheFuji --amount 3000000000000000000 --pay-fees-in LINK\n```\n\n4. Finally, send tokens by providing the array of `{token, amount}` objects, using the `ccip-token-transfer-batch` task:\n\n```shell\nnpx hardhat ccip-token-transfer-batch\n--source-blockchain \u003csourceBlockchain\u003e\n--basic-token-sender-address \u003caddressOfBasicTokenSenderContractWeDeployed\u003e\n--destination-blockchain \u003cdestinationBlockchain\u003e\n--receiver \u003creceiverAddressOnDestinationBlockchain\u003e\n--token-amounts \u003ctokenAmounts\u003e\n--pay-fees-in \u003cNative | LINK\u003e\n--router \u003crouter\u003e # Optional\n```\n\nThe `payFeesIn` flag determines whether you are paying for CCIP fees with LINK tokens or native coins on the source blockchain (Pass \"Native\" or \"LINK\").\n\nFor example, to send 100 units of CCIP-BnM tokens from avalancheFuji to ethereumSepolia and pay fees in Avalanche Fuji LINK, run:\n\n```shell\nnpx hardhat ccip-token-transfer-batch --source-blockchain avalancheFuji --basic-token-sender-address \u003cBASIC_TOKEN_SENDER_ADDRESS\u003e --destination-blockchain ethereumSepolia --receiver \u003cRECEIVER_ADDRESS\u003e --token-amounts '[{\"token\":\"0xD21341536c5cF5EB1bcb58f6723cE26e8D8E90e4\",\"amount\":\"100\"}]' --pay-fees-in LINK\n```\n\n5. You can always withdraw tokens for Chainlink CCIP fees from the [`BasicTokenSender.sol`](./contracts/BasicTokenSender.sol) smart contract using the `withdraw` task. Note that the `--token-address` flag is optional. If not provided, native coins will be withdrawn.\n\n```shell\nnpx hardhat withdraw\n--beneficiary \u003cwithdrawTo\u003e\n--blockchain \u003cbasicTokenSenderBlockchain\u003e\n--from \u003cbasicTokenSenderAddress\u003e\n--token-address \u003ctokensToWithdraw\u003e # Optional, if left empty native coins will be withdrawn\n```\n\nFor example, to withdraw the Avalanche Fuji LINK you previously sent for Chainlink CCIP fees, run:\n\n```shell\nnpx hardhat withdraw --beneficiary \u003cBENEFICIARY_ADDRESS\u003e --blockchain avalancheFuji --from \u003cBASIC_TOKEN_SENDER_ADDRESS\u003e --token-address 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846\n```\n\n### Example 4 - Send \u0026 Receive Tokens and Data\n\nTo transfer tokens and data across multiple chains, follow the next steps:\n\n1. Deploy the [`ProgrammableTokenTransfers.sol`](./contracts/ProgrammableTokenTransfers.sol) smart contract to the **source blockchain**, using the `deploy-programmable-token-transfers` task:\n\n```shell\nnpx hardhat deploy-programmable-token-transfers\n--router \u003crouter\u003e # Optional\n```\n\nFor example, if you want to send a message from Ethereum Sepolia to Polygon Amoy type:\n\n```shell\nnpx hardhat deploy-programmable-token-transfers --network ethereumSepolia\n```\n\n2. Open Metamask and fund your contract with Native tokens. For example, if you want to send a message from Ethereum Sepolia to Polygon Amoy, you can send 0.1 Sepolia ETH to your contract.\n\n3. Open Metamask and fund your contract with Sepolia CCIP-BnM tokens. For example, if you want to send a message from Ethereum Sepolia to Polygon Amoy, you can send 0.0000000000000001 Sepolia CCIP-BnM to your contract.\n\n4. Deploy the [`ProgrammableTokenTransfers.sol`](./contracts/ProgrammableTokenTransfers.sol) smart contract to the **destination blockchain**:\n\nFor example, if you want to receive a message from Ethereum Sepolia on Polygon Amoy type:\n\n```shell\nnpx hardhat deploy-programmable-token-transfers --network polygonAmoy\n```\n\nAt this point, you have one **sender** contract on the source blockchain, and one **receiver** contract on the destination blockchain. Please note that [`ProgrammableTokenTransfers.sol`](./contracts/ProgrammableTokenTransfers.sol) can both send \u0026 receive tokens and data, hence we have two identical instances on both source and destination blockchains.\n\n5. Send a message, by running:\n\n```shell\nnpx hardhat send-token-and-data\n--source-blockchain \u003csourceBlockchain\u003e\n--sender \u003caddressOfProgrammableTokenTransfersOnSourceBlockchain\u003e\n--destination-blockchain \u003cdestinationBlockchain\u003e\n--receiver \u003cddressOfProgrammableTokenTransfersOnDestinationBlockchain\u003e\n--message \u003cmessageToSend\u003e\n--token-address \u003ctokenToSendAddressOnSourceBlockchain\u003e\n--amount \u003camountToSend\u003e\n--router \u003crouter\u003e # Optional\n```\n\nFor example, if you want to send a \"Hello World\" message alongside 100 Sepolia CCIP-BnM from Ethereum Sepolia to Polygon Amoy type:\n\n```shell\nnpx hardhat send-token-and-data --source-blockchain ethereumSepolia --sender \u003cCONTRACT_ADDRESS_ON_SOURCE_BLOCKCHAIN\u003e --destination-blockchain polygonAmoy --receiver \u003cCONTRACT_ADDRESS_ON_DESTINATION_BLOCKCHAIN\u003e --message \"Hello World\" --token-address 0xFd57b4ddBf88a4e07fF4e34C487b99af2Fe82a05 --amount 100\n```\n\n6. 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:\n\n```shell\nnpx hardhat get-received-message-details\n--blockchain \u003cdestinationBlockchain\u003e\n--contract-address \u003cprogrammableTokenTransfersAddressOnDestinationBlockchain\u003e\n```\n\nFor example,\n\n```shell\nnpx hardhat get-received-message-details --blockchain polygonAmoy --contract-address \u003cPROGRAMMABLE_TOKEN_TRANSFERS_ADDRESS_ON_DESTINATION_BLOCKCHAIN\u003e\n```\n\n### Example 5 - Send \u0026 Receive Cross-Chain Messages and Pay with Native Coins\n\nTo send simple Text Cross-Chain Messages and pay for CCIP fees in Native Tokens, follow the next steps:\n\n1. Deploy the [`BasicMessageSender.sol`](./contracts/BasicMessageSender.sol) smart contract on the **source blockchain**, using the `deploy-basic-message-sender` task:\n\n```shell\nnpx hardhat deploy-basic-message-sender\n--router \u003crouterAddress\u003e # Optional\n--link \u003clinkTokenAddress\u003e # Optional\n```\n\nFor example, if you want to send a simple cross-chain message from Ethereum Sepolia, run\n\n```shell\nnpx hardhat deploy-basic-message-sender --network ethereumSepolia\n```\n\n2. Fund the [`BasicMessageSender.sol`](./contracts/BasicMessageSender.sol) smart contract with Native Coins, either manually using your wallet or by using the `fill-sender` task.\n\nFor example, if you want to send 0.01 Sepolia ether, run:\n\n```shell\nnpx hardhat fill-sender --sender-address \u003cBASIC_MESSAGE_SENDER_ADDRESS\u003e --blockchain ethereumSepolia --amount 10000000000000000 --pay-fees-in Native\n```\n\n3. Deploy the [`BasicMessageReceiver.sol`](./contracts/BasicMessageReceiver.sol) smart contract to the **destination blockchain**, using the `deploy-basic-message-receiver` task.\n\nFor example, if you want to receive a simple cross-chain message on the Avalanche Fuji blockchain, run:\n\n```shell\nnpx hardhat deploy-basic-message-receiver --network avalancheFuji\n```\n\n4. Finally, send a cross-chain message using the `send-message` task:\n\n```shell\nnpx hardhat send-message\n--source-blockchain \u003csourceBlockchain\u003e\n--sender \u003caddressOfBasicMessageSenderOnSourceBlockchain\u003e\n--destination-blockchain \u003cdestinationBlockchain\u003e\n--receiver \u003caddressOfBasicMessageReceiverOnDestinationBlockchain\u003e\n--message \u003cmessageToSend\u003e\n--pay-fees-in \u003cNative\u003e\n```\n\nFor example, if you want to send a \"Hello, World!\" message type:\n\n```shell\nnpx hardhat send-message --source-blockchain ethereumSepolia --sender \u003cBASIC_MESSAGE_SENDER_ADDRESS\u003e --destination-blockchain avalancheFuji --receiver \u003cBASIC_MESSAGE_RECEIVER_ADDRESS\u003e --message 'Hello, World!' --pay-fees-in Native\n```\n\n5. Once the CCIP message is finalized on the destination blockchain, you can query the latest received message details, using the `get-message` task:\n\n![ccip-explorer](./img/ccip-explorer.png)\n\n```shell\nnpx hardhat get-message\n--blockchain \u003cdestinationBlockchain\u003e\n--receiver-address \u003cbasicMessageReceiverAddress\u003e\n```\n\nFor example, to get the message details sent in the previous step, type:\n\n```shell\nnpx hardhat get-message --blockchain avalancheFuji --receiver-address \u003cBASIC_MESSAGE_RECEIVER_ADDRESS\u003e\n```\n\n6. You can always withdraw tokens for Chainlink CCIP fees from the [`BasicMessageSender.sol`](./contracts/BasicMessageSender.sol) smart contract using the `withdraw` task. Note that the `--token-address` flag is optional. If not provided, native coins will be withdrawn.\n\n```shell\nnpx hardhat withdraw\n--beneficiary \u003cwithdrawTo\u003e\n--blockchain \u003cbasicMessageSenderBlockchain\u003e\n--from \u003cbasicMessageSenderAddress\u003e\n--token-address \u003ctokensToWithdraw\u003e # Optional, if left empty native coins will be withdrawn\n```\n\nFor example, to withdraw Sepolia ether previously sent for Chainlink CCIP fees, run:\n\n```shell\nnpx hardhat withdraw --beneficiary \u003cBENEFICIARY_ADDRESS\u003e --blockchain ethereumSepolia --from \u003cBASIC_MESSAGE_SENDER_ADDRESS\u003e\n```\n\n### Example 6 - Send \u0026 Receive Cross-Chain Messages and Pay with LINK Tokens\n\nTo send simple Text Cross-Chain Messages and pay for CCIP fees in LINK Tokens, follow the next steps:\n\n1. Deploy the [`BasicMessageSender.sol`](./contracts/BasicMessageSender.sol) smart contract on the **source blockchain**, using the `deploy-basic-message-sender` task:\n\n```shell\nnpx hardhat deploy-basic-message-sender\n--router \u003crouterAddress\u003e # Optional\n--link \u003clinkTokenAddress\u003e # Optional\n```\n\nFor example, if you want to send a simple cross-chain message from Ethereum Sepolia, run\n\n```shell\nnpx hardhat deploy-basic-message-sender --network ethereumSepolia\n```\n\n2. Fund the [`BasicMessageSender.sol`](./contracts/BasicMessageSender.sol) smart contract with Testnet LINKs, either manually using your wallet or by using the `fill-sender` task.\n\nFor example, if you want to send 1 Sepolia LINK, run:\n\n```shell\nnpx hardhat fill-sender --sender-address \u003cBASIC_MESSAGE_SENDER_ADDRESS\u003e --blockchain ethereumSepolia --amount 1000000000000000000 --pay-fees-in LINK\n```\n\n3. Deploy the [`BasicMessageReceiver.sol`](./contracts/BasicMessageReceiver.sol) smart contract to the **destination blockchain**, using the `deploy-basic-message-receiver` task.\n\nFor example, if you want to receive a simple cross-chain message on the Avalanche Fuji blockchain, run:\n\n```shell\nnpx hardhat deploy-basic-message-receiver --network avalancheFuji\n```\n\n4. Finally, send a cross-chain message using the `send-message` task:\n\n```shell\nnpx hardhat send-message\n--source-blockchain \u003csourceBlockchain\u003e\n--sender \u003caddressOfBasicMessageSenderOnSourceBlockchain\u003e\n--destination-blockchain \u003cdestinationBlockchain\u003e\n--receiver \u003cddressOfBasicMessageReceiverOnDestinationBlockchain\u003e\n--message \u003cmessageToSend\u003e\n--pay-fees-in \u003cLINK\u003e\n```\n\nFor example, if you want to send a \"Hello, World!\" message type:\n\n```shell\nnpx hardhat send-message --source-blockchain ethereumSepolia --sender \u003cBASIC_MESSAGE_SENDER_ADDRESS\u003e --destination-blockchain avalancheFuji --receiver \u003cBASIC_MESSAGE_RECEIVER_ADDRESS\u003e --message 'Hello, World!' --pay-fees-in LINK\n```\n\n5. Once the CCIP message is finalized on the destination blockchain, you can query the latest received message details, using the `get-message` task:\n\n![ccip-explorer](./img/ccip-explorer.png)\n\n```shell\nnpx hardhat get-message\n--blockchain \u003cdestinationBlockchain\u003e\n--receiver-address \u003cbasicMessageReceiverAddress\u003e\n```\n\nFor example, to get the message details sent in the previous step, type:\n\n```shell\nnpx hardhat get-message --blockchain avalancheFuji --receiver-address \u003cBASIC_MESSAGE_RECEIVER_ADDRESS\u003e\n```\n\n6. You can always withdraw tokens for Chainlink CCIP fees from the [`BasicMessageSender.sol`](./contracts/BasicMessageSender.sol) smart contract using the `withdraw` task. Note that the `--token-address` flag is optional. If not provided, native coins will be withdrawn.\n\n```shell\nnpx hardhat withdraw\n--beneficiary \u003cwithdrawTo\u003e\n--blockchain \u003cbasicMessageSenderBlockchain\u003e\n--from \u003cbasicMessageSenderAddress\u003e\n--token-address \u003ctokensToWithdraw\u003e # Optional, if left empty native coins will be withdrawn\n```\n\nFor example, to withdraw Sepolia LINK previously sent for Chainlink CCIP fees, run:\n\n```shell\nnpx hardhat withdraw --beneficiary \u003cBENEFICIARY_ADDRESS\u003e --blockchain ethereumSepolia --from \u003cBASIC_MESSAGE_SENDER_ADDRESS\u003e --token-address 0x779877A7B0D9E8603169DdbD7836e478b4624789\n```\n\n### Example 7 - Execute Received Message as a Function Call\n\nOur 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.\n\nThe basic architecture diagram of what we want to accomplish looks like this:\n\n```mermaid\nflowchart LR\nsubgraph \"Source Blockchain\"\na(\"SourceMinter.sol\") -- \"`send abi.encodeWithSignature('mint(address)', msg.sender);`\" --\u003e b(\"Source Router\")\nend\n\nb(\"Source Router\") --\u003e c(\"CCIP\")\n\nc(\"CCIP\") --\u003e d(\"Destination Router\")\n\nsubgraph \"Destination Blockchain\"\nd(\"Destination Router\") -- \"`receive abi.encodeWithSignature('mint(address)', msg.sender);`\" --\u003e e(\"DestinationMinter.sol\")\ne(\"DestinationMinter.sol\") -- \"`call mint(to)`\" --\u003e f(\"MyNFT.sol\")\nend\n```\n\n1. Deploy the [`MyNFT.sol`](./contracts/cross-chain-nft-minter/MyNFT.sol) and [`DestinationMinter.sol`](./contracts/cross-chain-nft-minter/DestinationMinter.sol) smart contracts from the `./contracts/cross-chain-nft-minter` folder on the **destination blockchain**, by running the `deploy-destination-cross-chain-nft-minter` task:\n\n```shell\nnpx hardhat deploy-destination-cross-chain-nft-minter\n--router \u003crouterAddress\u003e # Optional\n```\n\nFor example, if you want to mint NFTs on Ethereum Sepolia, run:\n\n```shell\nnpx hardhat deploy-destination-cross-chain-nft-minter --network ethereumSepolia\n```\n\n2. Deploy the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract on the **source blockchain**, by running the `deploy-source-cross-chain-nft-minter` task:\n\n```shell\nnpx hardhat deploy-source-cross-chain-nft-minter\n--router \u003crouterAddress\u003e # Optional\n--link \u003clinkTokenAddress\u003e # Optional\n```\n\nFor example, if you want to mint NFTs on avalancheFuji by sending requests from Avalanche Fuji, run:\n\n```shell\nnpx hardhat deploy-source-cross-chain-nft-minter --network avalancheFuji\n```\n\n3. Fund the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract with tokens for CCIP fees.\n\n- If you want to pay for CCIP fees in Native tokens:\n\n  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 1 AVAX to the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract.\n\n  Or, you can execute the `fill-sender` task, by running:\n\n```shell\nnpx hardhat fill-sender\n--sender-address \u003csourceMinterAddress\u003e\n--blockchain \u003cblockchain\u003e\n--amount \u003camountToSend\u003e\n--pay-fees-in \u003cNative\u003e\n```\n\nFor example, if you want to fund it with 1 Avalanche Fuji AVAX, run:\n\n```shell\nnpx hardhat fill-sender --sender-address \u003cSOURCE_MINTER_ADDRESS\u003e --blockchain avalancheFuji --amount 1000000000000000000 --pay-fees-in Native\n```\n\n- If you want to pay for CCIP fees in LINK tokens:\n\n  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 Avalanche Fuji LINK to the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract.\n\n  Or, you can execute the `fill-sender` task, by running:\n\n```shell\nnpx hardhat fill-sender\n--sender-address \u003csourceMinterAddress\u003e\n--blockchain \u003cblockchain\u003e\n--amount \u003camountToSend\u003e\n--pay-fees-in \u003cLINK\u003e\n```\n\nFor example, if you want to fund it with 1 Avalanche Fuji LINK, run:\n\n```shell\nnpx hardhat fill-sender --sender-address \u003cSOURCE_MINTER_ADDRESS\u003e --blockchain avalancheFuji --amount 1000000000000000000 --pay-fees-in LINK\n```\n\n4. Mint NFTs by calling the `mint()` function of the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract on the **source blockchain**. It will send the CCIP Cross-Chain Message with the ABI-encoded mint function signature from the [`MyNFT.sol`](./contracts/cross-chain-nft-minter/MyNFT.sol) smart contract. The [`DestinationMinter.sol`](./contracts/cross-chain-nft-minter/DestinationMinter.sol) smart contracts will receive the CCIP Cross-Chain Message with the ABI-encoded mint function signature as a payload and call the [`MyNFT.sol`](./contracts/cross-chain-nft-minter/MyNFT.sol) smart contract using it. The [`MyNFT.sol`](./contracts/cross-chain-nft-minter/MyNFT.sol) smart contract will then mint the new NFT to the `msg.sender` account from the `mint()` function of the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract, a.k.a to the account from which you will call the following command:\n\n```shell\nnpx hardhat cross-chain-mint\n--source-minter \u003csourceMinterAddress\u003e\n--source-blockchain \u003csourceBlockchain\u003e\n--destination-blockchain \u003cdestinationBlockchain\u003e\n--destination-minter \u003cdestinationMinterAddress\u003e\n--pay-fees-in \u003cNative | LINK\u003e\n```\n\nFor example, if you want to mint NFTs on Ethereum Sepolia by sending requests from Avalanche Fuji and pay fees in LINK, run:\n\n```shell\nnpx hardhat cross-chain-mint --source-minter \u003cSOURCE_MINTER_ADDRESS\u003e --source-blockchain avalancheFuji --destination-blockchain ethereumSepolia --destination-minter \u003cDESTNATION_MINTER_ADDRESS\u003e --pay-fees-in LINK\n```\n\n5. 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:\n\n![ccip-explorer](./img/ccip-explorer.png)\n\n```shell\nnpx hardhat cross-chain-mint-balance-of\n--my-nft \u003cmyNftContractAddress\u003e\n--blockchain \u003cdestinationBlockchain\u003e\n--owner \u003ctheAccountToCheckBalanceOf\u003e\n```\n\nFor example, to verify that the new MyNFT was minted, type:\n\n```shell\nnpx hardhat cross-chain-mint-balance-of --my-nft \u003cMY_NFT_CONTRACT_ADDRESS\u003e --blockchain ethereumSepolia --owner \u003cPUT_YOUR_EOA_ADDRESS_HERE\u003e\n```\n\nOf course, you can see your newly minted NFT on popular NFT Marketplaces, like OpenSea for instance:\n\n![opensea](./img/opensea.png)\n\n6. You can always withdraw tokens for Chainlink CCIP fees from the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) smart contract using the `withdraw` task. Note that the `--token-address` flag is optional. If not provided, native coins will be withdrawn.\n\n```shell\nnpx hardhat withdraw\n--beneficiary \u003cwithdrawTo\u003e\n--blockchain \u003csourceMinterBlockchain\u003e\n--from \u003csourceMinterAddress\u003e\n--token-address \u003ctokensToWithdraw\u003e # Optional, if left empty native coins will be withdrawn\n```\n\nFor example, to withdraw tokens previously sent for Chainlink CCIP fees, run:\n\n```shell\nnpx hardhat withdraw --beneficiary \u003cBENEFICIARY_ADDRESS\u003e --blockchain avalancheFuji --from \u003cSOURCE_MINTER_ADDRESS\u003e\n```\n\nor\n\n```shell\nnpx hardhat withdraw --beneficiary \u003cBENEFICIARY_ADDRESS\u003e --blockchain avalancheFuji --from \u003cSOURCE_MINTER_ADDRESS\u003e --token-address 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846\n```\n\ndepending on whether you filled the [`SourceMinter.sol`](./contracts/cross-chain-nft-minter/SourceMinter.sol) contract with `Native` or `LINK` in step number 3.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmartcontractkit%2Fccip-starter-kit-hardhat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmartcontractkit%2Fccip-starter-kit-hardhat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmartcontractkit%2Fccip-starter-kit-hardhat/lists"}