Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Example 01: Token Transfer + Fast Transfers (FTF)

This example sends one token transfer message using ExtraArgsV3 with Fast Transfers (blockConfirmations > 0).

Script path: script/examples/Example01.s.sol

What You Will Do

  1. Mint 1 CCIP-BnM token to your EOA with script/Faucet.s.sol.
  2. (Optional) Read the executor allowed finality config (FinalityCodec bytes4) on the source chain.
  3. Send that token from source chain to destination chain with script/examples/Example01.s.sol.

Before You Start

Important: Keystore first

Use a local keystore account for script execution:

cast wallet import myAccount --interactive
Enter private key:
Enter password:
`myAccount` keystore was saved successfully. Address: <YOUR_EOA_ADDRESS_SHOULD_APPEAR_HERE>

This chapter assumes --account myAccount.

Step 1: Get 1 CCIP-BnM Token

Use the faucet script on the source chain:

forge script script/Faucet.s.sol:Faucet \
  --rpc-url ethereumSepolia \
  --account myAccount \
  --broadcast \
  --sig "run(address)" \
  <CCIP_BNM_SOURCE_TOKEN_ADDRESS>

Step 2: (Optional) Check Executor Allowed Finality

Before choosing a Fast Transfers depth in ExtraArgsV3, you can read what finality modes the Executor allows. The on-chain API is getAllowedFinalityConfig() → bytes4, encoded with FinalityCodec (same family of values as requestedFinalityConfig in your message’s ExtraArgs).

From a shell (replace RPC and address):

cast call <EXECUTOR_ADDRESS> "getAllowedFinalityConfig()(bytes4)" --rpc-url ethereumSepolia

Why this matters:

  • Your requested finality (derived from blockConfirmations in EncodeExtraArgsOffchain / Example01 via FinalityCodec._encodeBlockDepth) must be permitted by the executor’s dynamic config; otherwise the send can revert.

Check the source pool, executor, and CCV finality settings before sending:

forge script script/examples/Example06.s.sol:Example06CheckFinalityGates \
  --rpc-url ethereumSepolia \
  --sig "run(address,uint64,address,uint16)" \
  <SOURCE_ROUTER> <DESTINATION_CHAIN_SELECTOR> <CCIP_BNM_SOURCE_TOKEN_ADDRESS> <BLOCK_CONFIRMATIONS_GT_ZERO>

A quote alone does not prove ccipSend will succeed with a non-IPoolV2 pool.

Step 3: Send Token With Fast Transfers

Run Example01:

forge script script/examples/Example01.s.sol:Example01 \
  --rpc-url ethereumSepolia \
  --account myAccount \
  --broadcast \
  --sig "run(address,uint64,address,address,uint256,uint32,uint16,address)" \
  <SOURCE_ROUTER> \
  <DESTINATION_CHAIN_SELECTOR> \
  <RECEIVER_ON_DESTINATION_CHAIN> \
  <CCIP_BNM_SOURCE_TOKEN_ADDRESS> \
  <AMOUNT> \
  <GAS_LIMIT> \
  <BLOCK_CONFIRMATIONS_GT_ZERO> \
  <FEE_TOKEN_ADDRESS>

Parameter notes:

  • <AMOUNT>: token amount in token decimals (for 18 decimals, 1e18 is 1 token).
  • <GAS_LIMIT>: set to 0 for token-only transfer to an EOA receiver.
  • <BLOCK_CONFIRMATIONS_GT_ZERO>: must be > 0 and meet the source pool and executor minimums from Step 2.
  • <FEE_TOKEN_ADDRESS>: Pass the LINK token address on the source chain here. If you want to pay for CCIP fees in native coin instead, pass 0x0000000000000000000000000000000000000000

Verify Result

Example01 logs the message ID.

Use that ID in the CCIP Explorer to monitor status:

  • https://ccip.chain.link