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
- Mint 1 CCIP-BnM token to your EOA with
script/Faucet.s.sol. - (Optional) Read the executor allowed finality config (
FinalityCodecbytes4) on the source chain. - 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
blockConfirmationsinEncodeExtraArgsOffchain/Example01viaFinalityCodec._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,1e18is 1 token).<GAS_LIMIT>: set to0for token-only transfer to an EOA receiver.<BLOCK_CONFIRMATIONS_GT_ZERO>: must be> 0and 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, pass0x0000000000000000000000000000000000000000
Verify Result
Example01 logs the message ID.
Use that ID in the CCIP Explorer to monitor status:
- https://ccip.chain.link