Chainlink CCIP
The Chainlink CCIP adapter enables secure cross-chain token transfers and arbitrary messaging between Tenzro Network and other blockchains using Chainlink's Cross-Chain Interoperability Protocol. CCIP leverages Chainlink's proven decentralized oracle network infrastructure to provide enterprise-grade security and reliability.
Overview
Chainlink Cross-Chain Interoperability Protocol (CCIP) is a secure, reliable messaging protocol designed for enterprise-grade cross-chain communication. Unlike traditional bridges that rely on federated multisigs or optimistic fraud proofs, CCIP uses Chainlink's battle-tested oracle infrastructure combined with additional layers of security.
The Tenzro Network CCIP adapter (ChainlinkCcipAdapter) integrates with Chainlink CCIP Router contracts to provide:
- Secure cross-chain messaging with cryptographic proofs
- Native and wrapped token transfers with CCIP token pools
- Lane-based routing with configurable security parameters
- Rate limiting and anomaly detection
- Risk management through the Risk Management Network
- Programmable token transfers with data payloads
Architecture
The CCIP adapter is part of the tenzro-bridge crate, implementing the BridgeAdapter trait for unified cross-chain operations. The architecture consists of three main layers:
┌─────────────────────────────────────────┐
│ Application Layer │
│ (Tenzro Node, Smart Contracts) │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ ChainlinkCcipAdapter │
│ - Route messages via CCIP Router │
│ - Manage token pool interactions │
│ - Track lane configurations │
└───────────────┬─────────────────────────┘
│
┌───────────────▼─────────────────────────┐
│ Chainlink CCIP Protocol │
│ - OnRamp (source chain) │
│ - OffRamp (destination chain) │
│ - Committing DON (Decentralized │
│ Oracle Network) │
│ - Executing DON │
│ - Risk Management Network │
└─────────────────────────────────────────┘Key Concepts
Lanes
CCIP organizes cross-chain routes as "lanes" — unidirectional paths from a source chain to a destination chain. Each lane has independent configuration for:
- Rate limits — Maximum tokens/messages per time window
- Fee structure — Gas costs and LINK payment requirements
- Supported tokens — Which tokens can travel this lane
- Security parameters — Confirmation depths, oracle counts
use tenzro_bridge::adapters::ChainlinkCcipAdapter;
use tenzro_bridge::types::ChainType;
// Configure a lane from Tenzro to Ethereum
let lane_config = CcipLaneConfig {
source_chain: ChainType::Tenzro,
destination_chain: ChainType::Ethereum,
on_ramp_address: "0x1a44076050125825900e736c501f859c50fE728c".to_string(),
off_ramp_address: "0x2b8C6B4F2e8e1c2B6D0e3a7F9c8B7A6D5E4C3B2A".to_string(),
rate_limit_capacity: 1_000_000_000_000_000_000_000, // 1000 TNZO
rate_limit_rate: 10_000_000_000_000_000_000, // 10 TNZO/sec refill
enabled: true,
};
adapter.configure_lane(lane_config).await?;OnRamp and OffRamp
CCIP uses OnRamp and OffRamp contracts to manage cross-chain message flow:
- OnRamp (Source Chain) — Accepts messages and tokens, emits events for DON to observe
- OffRamp (Destination Chain) — Receives attestations from DON, delivers messages and tokens
The Committing DON reads events from OnRamp contracts, creates Merkle roots of message batches, and writes these roots to OffRamp contracts. The Executing DON then provides Merkle proofs to deliver individual messages.
Risk Management Network
CCIP includes a secondary Risk Management Network that monitors all cross-chain activity for anomalies. If suspicious activity is detected, the Risk Management Network can pause lanes or freeze token transfers, providing an additional security layer independent of the primary DON.
Configuration
Configure the CCIP adapter through ChainlinkCcipConfig:
use tenzro_bridge::adapters::ChainlinkCcipConfig;
let config = ChainlinkCcipConfig {
router_address: "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D".to_string(),
chain_selector: 5009297550715157269, // Tenzro chain selector
link_token_address: "0x514910771AF9Ca656af840dff83E8264EcF986CA".to_string(),
wrapped_native_address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2".to_string(),
rpc_url: "https://rpc.tenzro.network".to_string(),
};
let adapter = ChainlinkCcipAdapter::new(config).await?;Configuration Parameters:
router_address— CCIP Router contract address on Tenzrochain_selector— Unique CCIP identifier for Tenzro Networklink_token_address— LINK token contract for fee paymentwrapped_native_address— Wrapped TNZO (WTNZO) contract addressrpc_url— JSON-RPC endpoint for Tenzro node
Usage Examples
Sending a Cross-Chain Message
use tenzro_bridge::types::{TenzroMessage, ChainType};
// Create a message to Polygon
let message = TenzroMessage {
source_chain: ChainType::Tenzro,
destination_chain: ChainType::Polygon,
payload: serde_json::to_vec(&json!({
"action": "execute_governance",
"proposal_id": 42,
"votes": 1_000_000
}))?,
nonce: 100,
sender: sender_address.clone(),
signature: None,
signer_public_key: None,
};
// Estimate LINK fee
let fee_estimate = adapter.estimate_fee(
&ChainType::Polygon,
message.payload.len()
).await?;
println!("Estimated LINK fee: {} juels", fee_estimate);
// Send message via CCIP
let message_id = adapter.send_message(message).await?;
println!("CCIP message ID: {}", message_id);Transferring Tokens with Data
CCIP's unique feature is programmable token transfers — combining token transfers with arbitrary data payloads:
use tenzro_bridge::types::{BridgeTransfer, BridgeAsset};
// Transfer TNZO to Arbitrum with execution data
let transfer = BridgeTransfer {
id: uuid::Uuid::new_v4().to_string(),
source_chain: ChainType::Tenzro,
destination_chain: ChainType::Arbitrum,
asset: BridgeAsset::Tnzo,
amount: 100_000_000_000_000_000_000, // 100 TNZO
sender: sender_address.clone(),
recipient: recipient_contract.clone(),
status: TransferStatus::Pending,
tx_hash: None,
created_at: chrono::Utc::now(),
completed_at: None,
};
// Attach execution data (e.g., DEX swap parameters)
let execution_data = json!({
"function": "swap",
"slippage": 0.5,
"min_output": "95000000000000000000"
});
// Bridge with data payload
let tx_hash = adapter.bridge_tokens_with_data(
transfer,
serde_json::to_vec(&execution_data)?
).await?;
println!("Programmatic transfer sent: {}", tx_hash);Monitoring Transfer Status
// Poll for message delivery
let message_id = "0x1234...";
loop {
let status = adapter.get_message_status(message_id).await?;
match status {
MessageStatus::Committed => {
println!("Message committed to destination chain");
}
MessageStatus::Executed => {
println!("Message executed successfully!");
break;
}
MessageStatus::Failed(reason) => {
eprintln!("Message execution failed: {}", reason);
break;
}
MessageStatus::Pending => {
tokio::time::sleep(Duration::from_secs(30)).await;
}
}
}Token Pools
CCIP uses token pools to manage token transfers. Each supported token has a pool contract on both source and destination chains:
- Lock and Mint — Lock tokens on source, mint on destination
- Burn and Mint — Burn on source, mint on destination (for native tokens)
- Lock and Unlock — Lock on source, unlock on destination (for wrapped tokens)
// Register TNZO token pool for CCIP transfers
let pool_config = TokenPoolConfig {
token_address: "0x...TNZO_TOKEN_ADDRESS",
pool_type: PoolType::BurnAndMint,
chain_selector: 5009297550715157269,
remote_pool_addresses: vec![
("ethereum".to_string(), "0x...ETH_POOL_ADDRESS".to_string()),
("polygon".to_string(), "0x...POLYGON_POOL_ADDRESS".to_string()),
],
rate_limit_enabled: true,
max_capacity: 10_000_000_000_000_000_000_000, // 10,000 TNZO
};
adapter.register_token_pool(pool_config).await?;Fee Payment Options
CCIP supports two fee payment methods:
- LINK tokens — Pay fees in LINK for cross-chain messages
- Native gas tokens — Pay fees in TNZO (converted to LINK by CCIP)
// Pay with LINK tokens (recommended)
let fee_in_link = adapter.estimate_fee_in_link(
&ChainType::Ethereum,
message.payload.len()
).await?;
adapter.send_message_with_link_payment(message.clone(), fee_in_link).await?;
// Pay with native TNZO
let fee_in_native = adapter.estimate_fee_in_native(
&ChainType::Ethereum,
message.payload.len()
).await?;
adapter.send_message_with_native_payment(message, fee_in_native).await?;Security Model
CCIP provides defense-in-depth security through multiple layers:
Layer 1: Decentralized Oracle Networks
Multiple independent oracle nodes operated by reputable node operators (validators, custodians, infrastructure providers) observe source chain events and commit message batches to destination chains.
Layer 2: Risk Management Network
A separate network of nodes monitors for anomalies (unusual volumes, suspicious contracts, known exploits) and can pause lanes if threats are detected.
Layer 3: Rate Limiting
Token buckets with configurable capacity and refill rates prevent rapid drainage of token pools even if other security layers are compromised.
Layer 4: Message Verification
All messages include cryptographic signatures verified on-chain. Tenzro extends this with additional signature verification:
// Verify CCIP message authenticity
let incoming_message = receive_ccip_message().await?;
// CCIP verifies Merkle proofs and DON signatures
// Tenzro also verifies application-level signature
let verification = incoming_message.verify_signature()?;
if !verification.is_valid {
return Err("Invalid sender signature");
}
// Check rate limits haven't been exceeded
if adapter.check_rate_limit_exceeded(&incoming_message).await? {
return Err("Rate limit exceeded for this lane");
}
process_verified_message(incoming_message).await?;Error Handling
use tenzro_bridge::error::BridgeError;
match adapter.send_message(message).await {
Ok(message_id) => {
println!("CCIP message sent: {}", message_id);
}
Err(BridgeError::RateLimitExceeded) => {
eprintln!("Lane rate limit exceeded, try again later");
}
Err(BridgeError::InsufficientLinkBalance) => {
eprintln!("Insufficient LINK tokens for fee payment");
}
Err(BridgeError::UnsupportedDestination(chain)) => {
eprintln!("No CCIP lane configured for {:?}", chain);
}
Err(BridgeError::TokenPoolNotFound(token)) => {
eprintln!("Token {:?} not registered with CCIP", token);
}
Err(e) => {
eprintln!("CCIP error: {:?}", e);
}
}Supported Chains
Chainlink CCIP currently supports 15+ blockchain networks with more being added:
ChainType::Ethereum // Ethereum Mainnet ChainType::Arbitrum // Arbitrum One ChainType::Optimism // Optimism Mainnet ChainType::Polygon // Polygon PoS ChainType::Avalanche // Avalanche C-Chain ChainType::BnbChain // BNB Smart Chain ChainType::Base // Base (Coinbase L2) ChainType::Wemix // WEMIX3.0 ChainType::Kroma // Kroma // More chains continuously added
Bridge Router Integration
The CCIP adapter integrates with Tenzro's BridgeRouter for automatic adapter selection:
use tenzro_bridge::router::{BridgeRouter, RoutingStrategy};
let router = BridgeRouter::new(RoutingStrategy::Availability);
// Add CCIP adapter
router.add_adapter("ccip", Box::new(ccip_adapter)).await;
router.add_adapter("layerzero", Box::new(layerzero_adapter)).await;
// Router chooses CCIP for supported high-value transfers
// and LayerZero for lower-value, faster transfers
let transfer = BridgeTransfer { /* ... */ };
let result = router.route_transfer(transfer).await?;Current Implementation Status
Development Status:
The CCIP adapter currently contains stub implementations for external chain interactions. The adapter structure, types, and API are production-ready, but actual CCIP Router contract calls are simulated.
See issue #48 in the production readiness audit. Real CCIP integration with live Router contracts is planned for Phase 8 of the development roadmap.
Roadmap
Planned improvements for the CCIP adapter:
- Real Router contract integration via JSON-RPC and ethers-rs
- Token pool management for TNZO and stTNZO
- Event listener for automatic message status updates
- Risk Management Network monitoring integration
- Dynamic lane configuration updates from on-chain state
- Testnet deployment with Ethereum Sepolia
- Integration with Tenzro settlement layer for atomic cross-chain payments