CCIP SDK: ccip-send (Data, Token, Token+Data)
CCIP SDK package
Install from NPM:
npm install @chainlink/ccip-sdk
This chapter shows how to run the SDK script for the three message shapes used in CCIP v2 examples:
- data-only
- token-only
- token+data
The script lives in sdk-examples/src/ccip-send.ts.
Receiver Compatibility for Fast Transfers (FTF)
When using --block-confirmations > 0 (Fast Transfers), receiver compatibility matters for message modes that execute receiver callbacks.
| Mode | --block-confirmations 0 | --block-confirmations > 0 |
|---|---|---|
data | baseline receiver works | destination receiver must allow the requested finality (see getCCVsAndFinalityConfig / allowedFinalityConfig) |
token-data | baseline receiver works | destination receiver must allow the requested finality (see getCCVsAndFinalityConfig / allowedFinalityConfig) |
token with --gas-limit 0 | callback not executed (EOA-style token receive path) | callback not executed (EOA-style token receive path) |
Terminology note:
- Sender side (
ExtraArgsV3): requested finality (e.g.FinalityCodec/ block depth inrequestedFinalityConfig) - Receiver side (
getCCVsAndFinalityConfig):allowedFinalityConfig(bytes4,FinalityCodec)
How This Script Uses the SDK
At a high level, the script builds EVMChain instances for source and destination, asks the SDK for a fee quote, then submits the message via the SDK send call.
import { EVMChain } from '@chainlink/ccip-sdk'
const source = await EVMChain.fromUrl(sourceRpcUrl)
const dest = await EVMChain.fromUrl(destRpcUrl)
const fee = await source.getFee({ router, destChainSelector: dest.network.chainSelector, message })
await source.sendMessage({ router, destChainSelector: dest.network.chainSelector, message: { ...message, fee }, wallet })
Prerequisites
Requires Node.js 24 or later (@chainlink/ccip-sdk 1.x uses syntax Node 22 cannot run).
From repo root:
npm --prefix sdk-examples install
For actual sends (non---dry-run), set USER_KEY (or PRIVATE_KEY) in the root .env.
RPC Configuration
ccip-send accepts RPC URLs either:
- directly via flags (
--source-rpc-url,--dest-rpc-url) - or from
.env:CCIP_SOURCE_RPC_URL,CCIP_DEST_RPC_URL- fallback:
ETHEREUM_SEPOLIA_RPC_URL,POLYGON_AMOY_RPC_URL
1) Data-Only
Fast Transfers (blockConfirmations=1):
npm --prefix sdk-examples run ccip-send -- \
--mode data \
--source-rpc-url "$ETHEREUM_SEPOLIA_RPC_URL" \
--dest-rpc-url "$POLYGON_AMOY_RPC_URL" \
--router <SOURCE_ROUTER> \
--receiver <RECEIVER> \
--block-confirmations 1
Default finality (blockConfirmations=0):
npm --prefix sdk-examples run ccip-send -- \
--mode data \
--source-rpc-url "$ETHEREUM_SEPOLIA_RPC_URL" \
--dest-rpc-url "$POLYGON_AMOY_RPC_URL" \
--router <SOURCE_ROUTER> \
--receiver <RECEIVER> \
--block-confirmations 0
2) Token-Only
Use Sepolia CCIP-BnM and the finality check from Example 01.
npm --prefix sdk-examples run ccip-send -- \
--mode token \
--source-rpc-url "$ETHEREUM_SEPOLIA_RPC_URL" \
--dest-rpc-url "$POLYGON_AMOY_RPC_URL" \
--router <SOURCE_ROUTER> \
--receiver <RECEIVER> \
--token <SEPOLIA_CCIP_BNM_TOKEN> \
--amount 1 \
--block-confirmations <BLOCK_CONFIRMATIONS_GT_ZERO>
3) Token + Data
Configure the Amoy receiver as in Example 03.
npm --prefix sdk-examples run ccip-send -- \
--mode token-data \
--source-rpc-url "$ETHEREUM_SEPOLIA_RPC_URL" \
--dest-rpc-url "$POLYGON_AMOY_RPC_URL" \
--router <SOURCE_ROUTER> \
--receiver <RECEIVER> \
--token <SEPOLIA_CCIP_BNM_TOKEN> \
--amount 1 \
--data "hello + token" \
--block-confirmations <BLOCK_CONFIRMATIONS_GT_ZERO>
If You Need Testnet Tokens
Mint Sepolia CCIP-BnM with the faucet task:
npx hardhat faucet --network <NETWORK_NAME> --ccip-bnm <SEPOLIA_CCIP_BNM_TOKEN>