Example 02: Hello World to BasicMessageReceiverWithCCVs with Fast Transfers (FTF)
This example deploys a destination BasicMessageReceiverWithCCVs contract and sends a Hello World data message from an EOA using Fast Transfers (blockConfirmations > 0).
Scripts used:
script/examples/Example02.s.sol:DeployBasicMessageReceiverWithCCVsscript/examples/Example02.s.sol:SetBasicMessageReceiverWithCCVsMinBlockDepthscript/examples/Example02.s.sol:Example02
What You Will Do
- Deploy
BasicMessageReceiverWithCCVson destination chain. - Configure minimum block depth for the source chain.
- Send a Hello World CCIP data message from source chain to
BasicMessageReceiverWithCCVs.
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.
Receiver Contract Context
Pre-v2.0
To receive CCIP messages (data or data+tokens), contracts implemented IAny2EVMMessageReceiver:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IAny2EVMMessageReceiver {
function ccipReceive(
Client.Any2EVMMessage calldata message
) external;
}
As a convenience, applications generally inherited CCIPReceiver.sol and implemented _ccipReceive.
CCIP v2.0
In v2.0, receivers expose Cross Chain Verifiers and finality requirements via getCCVsAndFinalityConfig (encoded with FinalityCodec as bytes4 allowedFinalityConfig):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IAny2EVMMessageReceiverV2 {
function ccipReceive(
Client.Any2EVMMessage calldata message
) external;
function getCCVsAndFinalityConfig(
uint64 sourceChainSelector,
bytes calldata sender
)
external
view
returns (
address[] memory requiredCCVs,
address[] memory optionalCCVs,
uint8 optionalThreshold,
bytes4 allowedFinalityConfig
);
}
The receiver controls two independent dimensions:
requiredCCVsandoptionalCCVsdefine additional verifiers required for acceptance.allowedFinalityConfigdefines which requested finality modes are accepted (seeFinalityCodecin chainlink-ccip). A zero value (WAIT_FOR_FINALITY_FLAG) means only fully finalized messages are accepted.
You can combine these independently (for example, add verifiers while requiring full finality, or allow Fast Transfers when policy allows).
In this starter kit, src/BasicMessageReceiverWithCCVs.sol adds configurable verifier sets and stores a per-chain minimum block depth, which it exposes via FinalityCodec._encodeBlockDepth in getCCVsAndFinalityConfig.
Step 1: Deploy BasicMessageReceiverWithCCVs on Destination Chain
Run:
forge script script/examples/Example02.s.sol:DeployBasicMessageReceiverWithCCVs \
--rpc-url polygonAmoy \
--account myAccount \
--broadcast \
--sig "run(address)" \
<DESTINATION_ROUTER>
Save the deployed address as <BASIC_MESSAGE_RECEIVER_WITH_CCVS_ADDRESS>.
By default, this receiver starts with minBlockDepth = 0 (default finality only) for all source chains.
Step 2: Configure Minimum Block Depth for Your Source Chain
Run:
forge script script/examples/Example02.s.sol:SetBasicMessageReceiverWithCCVsMinBlockDepth \
--rpc-url polygonAmoy \
--account myAccount \
--broadcast \
--sig "run(address,uint64,uint16)" \
<BASIC_MESSAGE_RECEIVER_WITH_CCVS_ADDRESS> \
<SOURCE_CHAIN_SELECTOR> \
<MIN_BLOCK_DEPTH>
For this chapter, use <MIN_BLOCK_DEPTH> = 1.
0means deafault finality-only behavior.> 0enables Fast Transfers with that minimum depth.
Step 3: Send Hello World Data Message from EOA
Run:
forge script script/examples/Example02.s.sol:Example02 \
--rpc-url ethereumSepolia \
--account myAccount \
--broadcast \
--sig "run(address,uint64,address,string,uint32,uint16,address)" \
<SOURCE_ROUTER> \
<DESTINATION_CHAIN_SELECTOR> \
<BASIC_MESSAGE_RECEIVER_WITH_CCVS_ADDRESS> \
"Hello, World" \
<GAS_LIMIT> \
<BLOCK_CONFIRMATIONS_GT_ZERO> \
<FEE_TOKEN_ADDRESS>
Parameter notes:
<GAS_LIMIT>must be> 0because the destination receiver callback needs gas.<BLOCK_CONFIRMATIONS_GT_ZERO>must be> 0for Fast Transfers.<BLOCK_CONFIRMATIONS_GT_ZERO>should be greater than or equal to<MIN_BLOCK_DEPTH>.- Executor may enforce a minimum block confirmations value and revert if too low.
- If requested confirmations exceed chain finality, default finality is used.
<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
Example02 logs a CCIP message ID.
Use that ID in the CCIP Explorer:
- https://ccip.chain.link
You can inspect receiver state on destination chain:
cast call <BASIC_MESSAGE_RECEIVER_WITH_CCVS_ADDRESS> "latestMessage()(bytes)" --rpc-url polygonAmoy