Example 06: CCT Burn and Mint
This example covers the full BurnMint CCT flow on Sepolia → Amoy:
- Deploy
CrossChainToken+ BurnMint pool on both chains (Hardhat Ignition). - Configure pools to trust each other (
example06-step1). - Enable Fast Transfers (FTF) on both pools and check the source lane gates.
- Send at default finality or Fast Transfers (
example06-step2). - Verify BurnMint behavior (burn on source, mint on destination) with helper tasks.
Modules and tasks used:
- Deploy token + pool: Hardhat Ignition module
ignition/modules/BurnMintTokenPool.ts(deploy on each chain with the appropriate parameters file). - Configure remote lane: Hardhat task
example06-step1. - Set pool FTF policy: Hardhat task
example06-set-pool-finality. - Inspect FTF gates: Hardhat task
example06-check-finality-gates. - Send CCIP token transfer: Hardhat task
example06-step2. - Verify: Helper tasks
token-admin-registry-get-pool,pool-get-remote-token,pool-get-remote-pools,erc20-balance-of,erc20-total-supply.
Before You Start
Important: Keystore first
Use a local keystore account for task execution:
npx hardhat keystore set SEPOLIA_PRIVATE_KEY npx hardhat keystore set AMOY_PRIVATE_KEY npx hardhat keystore set SEPOLIA_RPC_URL npx hardhat keystore set AMOY_RPC_URLEnsure
ignition/paramsAmoy.jsonandignition/paramsEthSepolia.jsoncontain the correctrouterAddress,armProxy,registryModuleOwnerCustom, andtokenAdminRegistryfor each chain.
Deployment Defaults
The BurnMintTokenPool Ignition module deploys:
- Token: CrossChainToken via
BaseERC20.ConstructorParams:TestToken(TEST), 18 decimals, 1_000_000 × 10¹⁸ premint, 100_000_000 × 10¹⁸ max supply. The deployer EOA is pre-mint recipient, CCIP admin, burn/mint admin, and default admin. Registration usesRegistryModuleOwnerCustom.registerAdminViaGetCCIPAdmin. - Pool: BurnMintTokenPool with no advanced pool hook (CCT 01).
Step 1: Deploy Token + Pool on Sepolia (source)
npx hardhat ignition deploy ignition/modules/BurnMintTokenPool.ts --network <NETWORK_NAME> --parameters <PARAMETERS_FILE>
--parameters is the path to the chain’s Ignition parameters JSON (e.g. ignition/paramsAmoy.json or ignition/paramsEthSepolia.json); it supplies router, arm proxy, token admin registry, and other addresses to the module.
Save from the deployment output:
<SEPOLIA_TOKEN_ADDRESS>(CrossChainToken)<SEPOLIA_POOL_ADDRESS>(BurnMintTokenPool)
Step 2: Deploy Token + Pool on Amoy (destination)
npx hardhat ignition deploy ignition/modules/BurnMintTokenPool.ts --network <NETWORK_NAME> --parameters <PARAMETERS_FILE>
Use the parameters file for the chain you are deploying to.
Save from the deployment output:
<AMOY_TOKEN_ADDRESS><AMOY_POOL_ADDRESS>
Step 3: Configure Sepolia Pool With Amoy Remote
npx hardhat example06-step1 --network <NETWORK_NAME> \
--local-pool <SEPOLIA_POOL_ADDRESS> \
--remote-chain-selector <AMOY_CHAIN_SELECTOR> \
--remote-token <AMOY_TOKEN_ADDRESS> \
--remote-pool <AMOY_POOL_ADDRESS>
Step 4: Configure Amoy Pool With Sepolia Remote
npx hardhat example06-step1 --network <NETWORK_NAME> \
--local-pool <AMOY_POOL_ADDRESS> \
--remote-chain-selector <SEPOLIA_CHAIN_SELECTOR> \
--remote-token <SEPOLIA_TOKEN_ADDRESS> \
--remote-pool <SEPOLIA_POOL_ADDRESS>
Step 5: Enable Fast Transfers on Both Pools
New pools allow full finality only (0x00000000). FTF is a pool setting; configure both pools:
npx hardhat example06-set-pool-finality --network <NETWORK_NAME> --local-pool <SEPOLIA_POOL_ADDRESS> --min-block-depth <MIN_BLOCK_DEPTH>
npx hardhat example06-set-pool-finality --network <NETWORK_NAME> --local-pool <AMOY_POOL_ADDRESS> --min-block-depth <MIN_BLOCK_DEPTH>
The task reads back each value. 0 disables FTF; 1–65535 set the minimum depth. The staged
wait-for-safe flag is not usable on this lane.
Step 6: Check the Finality Gates
npx hardhat example06-check-finality-gates --network <NETWORK_NAME> \
--source-router <SEPOLIA_ROUTER> \
--destination-chain-selector <DESTINATION_CHAIN_SELECTOR> \
--token-to-send <SEPOLIA_TOKEN_ADDRESS> \
--block-confirmations <BLOCK_CONFIRMATIONS_GT_ZERO>
The read-only task checks the pool, executor, and CCVs. A getFee quote alone does not prove
ccipSend will succeed for a non-IPoolV2 pool.
Step 7: Send BurnMint Transfer
npx hardhat example06-step2 --network <NETWORK_NAME> \
--source-router <SEPOLIA_ROUTER> \
--destination-chain-selector <DESTINATION_CHAIN_SELECTOR> \
--receiver <RECEIVER_ON_AMOY> \
--token-to-send <SEPOLIA_TOKEN_ADDRESS> \
--amount <AMOUNT> \
--gas-limit <GAS_LIMIT> \
--block-confirmations 0 \
--fee-token-address <FEE_TOKEN_ADDRESS>
Parameter notes:
--amount: token amount in wei (e.g.1000000000000000000for 1 token with 18 decimals).- For token-only transfer to an EOA receiver, use
--gas-limit 0. - This task uses ExtraArgsV3 with
blockConfirmations = 0(default finality). --fee-token-address: use0x0000000000000000000000000000000000000000for native fee, or the LINK token address on Sepolia for LINK fee.
For the FTF version, run the same task after Steps 5 and 6 with a permitted depth:
npx hardhat example06-step2 --network <NETWORK_NAME> \
--source-router <SEPOLIA_ROUTER> \
--destination-chain-selector <DESTINATION_CHAIN_SELECTOR> \
--receiver <RECEIVER_ON_AMOY> \
--token-to-send <SEPOLIA_TOKEN_ADDRESS> \
--amount <AMOUNT> \
--gas-limit <GAS_LIMIT> \
--block-confirmations <BLOCK_CONFIRMATIONS_GT_ZERO> \
--fee-token-address <FEE_TOKEN_ADDRESS>
Step 8: Verify BurnMint Behavior
Verify token→pool registration:
npx hardhat token-admin-registry-get-pool --network <NETWORK_NAME> --registry <TOKEN_ADMIN_REGISTRY> --token <TOKEN_ADDRESS>
Verify remote lane mapping (tasks decode bytes to address):
npx hardhat pool-get-remote-token --network <NETWORK_NAME> --pool <POOL_ADDRESS> --chain-selector <CHAIN_SELECTOR>
npx hardhat pool-get-remote-pools --network <NETWORK_NAME> --pool <POOL_ADDRESS> --chain-selector <CHAIN_SELECTOR>
Verify balances and supplies after transfer finalizes:
npx hardhat erc20-balance-of --network <NETWORK_NAME> --token <TOKEN_ADDRESS> --account <ACCOUNT_ADDRESS>
npx hardhat erc20-total-supply --network <NETWORK_NAME> --token <TOKEN_ADDRESS>
Monitor message status with the message ID on:
- https://ccip.chain.link