Skip to main content
Version: 1.14.0

CCIP SDK

TypeScript SDK for sending, tracking, and executing cross-chain messages on CCIP.

Package@chainlink/ccip-sdk
Version1.14.0
Node.jsv20+ (v24+ recommended)
LicenseMIT
note

This documentation covers the latest version. For previous versions, see the GitHub releases.

Installation​

Bash
npm install @chainlink/ccip-sdk

Quick Start​

TypeScript
import { EVMChain } from '@chainlink/ccip-sdk'

// Connect to Ethereum Sepolia
const chain = await EVMChain.fromUrl('https://rpc.sepolia.org')
console.log('Connected to:', chain.network.name)

// Fetch CCIP requests from a transaction
const requests = await chain.getMessagesInTx('0x...')
for (const req of requests) {
console.log('Message ID:', req.message.messageId)
console.log('Destination:', req.lane.destChainSelector)
}

Prerequisites​

You need RPC endpoints for the chains you want to interact with. Node.js v20+ is required (v24+ recommended for native fetch support).

  • QuickNode - Multi-chain support with free tier
  • Alchemy - Enterprise-grade with free tier
  • Chainlist.org - Free public RPCs for EVM networks
  • Infura - Reliable EVM endpoints with free tier
  • Nodereal - Aptos and EVM support with free tier
Tip: For quick testing, Chainlist.org provides free public RPCs. For production, use Alchemy or Infura for better rate limits.

Chain Support​

Supported chain families:
EVM iconEVMSolana iconSolanaAptos iconAptosTON iconTONCanton iconCanton

Quick Reference​

TaskMethodReference
Connect to chainEVMChain.fromUrl(rpcUrl)EVMChain
Track messagechain.getMessagesInTx(txHash)getMessagesInTx
Get feechain.getFee({ router, destChainSelector, message })getFee
Send messagechain.sendMessage({ router, destChainSelector, message, wallet })sendMessage
Manual execution (by message ID)dest.execute({ messageId, wallet })execute
Manual execution (by tx hash)source.getExecutionInput({ request, verifications })getExecutionInput
Check lane featureschain.getLaneFeatures({ router, destChainSelector })getLaneFeatures
Decode messagedecodeMessage(data)decodeMessage

Concepts​

Chain Classes​

ClassBlockchainImport
EVMChainEthereum, Arbitrum, Optimism, etc.import { EVMChain } from '@chainlink/ccip-sdk'
SolanaChainSolanaimport { SolanaChain } from '@chainlink/ccip-sdk'
AptosChainAptosimport { AptosChain } from '@chainlink/ccip-sdk'
SuiChainSuiimport { SuiChain } from '@chainlink/ccip-sdk'
TONChainTONimport { TONChain } from '@chainlink/ccip-sdk'
CantonChainCantonimport { CantonChain } from '@chainlink/ccip-sdk'

Message Lifecycle​

  1. Sent - Message emitted on source chain (CCIPRequest)
  2. Committed - Merkle root committed on destination (CommitReport)
  3. Executed - Message executed on destination (ExecutionReceipt)

Chain Selectors vs Chain IDs​

CCIP uses chain selectors (not chain IDs) to identify networks. Chain selectors are unique identifiers assigned by CCIP that remain consistent across the protocol.

TypeScript
import { networkInfo } from '@chainlink/ccip-sdk'

// Wrong: Using chain ID for CCIP operations
const destChain = 84532 // Base Sepolia chain ID - DON'T USE

// Correct: Using CCIP chain selector
const destSelector = networkInfo('ethereum-testnet-sepolia-base-1').chainSelector
// Returns: 10344971235874465080n

Always use chain selectors for:

  • destChainSelector in messages
  • Lane configuration
  • Fee estimation

Use networkInfo() to convert between chain IDs, names, and selectors.

Extra Arguments​

Configure gas limits and execution parameters. Pass them as an object — the SDK encodes internally:

TypeScript
const message = {
receiver: '0x...',
extraArgs: {
gasLimit: 200000n,
allowOutOfOrderExecution: true,
},
}

Error Handling​

The SDK throws typed errors:

TypeScript
import {
EVMChain,
CCIPMessageNotFoundInTxError,
CCIPBlockNotFoundError,
} from '@chainlink/ccip-sdk'

try {
const requests = await chain.getMessagesInTx(txHash)
} catch (error) {
if (error instanceof CCIPMessageNotFoundInTxError) {
console.log('No CCIP messages in transaction:', error.context.txHash)
} else if (error instanceof CCIPBlockNotFoundError) {
console.log('Block not found:', error.context.block)
} else {
throw error
}
}

See Error Handling for recovery patterns.

Next Steps​