Skip to content
Tenzro
← All tutorials
Tutorial · Execution and bridges

Send messages and TNZO with Chainlink CCIP

Quote, send and track a Chainlink CCIP message from a Tenzro node, inspect the TNZO cross-chain token pools and their rate limits, and move TNZO over CCIP.

Intermediate25 min

Chainlink CCIP is one of the bridges Tenzro Network 1 connects to. It carries arbitrary messages between chains and moves tokens through token pools under the Cross-Chain Token (CCT) standard, with per-lane rate limits. A Tenzro node exposes CCIP through the tenzro_ccip* and tenzro_cct* JSON-RPC methods and the tenzro ccip and tenzro cct CLI groups.

This tutorial covers two tasks:

  1. Send a message from one chain to another: quote the fee, build the ccipSend() call, sign it with your own wallet on the source chain, and track delivery.
  2. Move TNZO: inspect the TNZO CCT pools and their rate limits, then bridge TNZO through the CCIP adapter.

Prerequisites

  • The tenzro CLI (see CLI reference).
  • For the message: a wallet on the source chain with native gas, and a receiver contract on the destination chain that implements the CCIP receiver interface.
  • For TNZO: a funded Tenzro account. Fund it by transferring TNZO to its address from another wallet or account.
bash
export RPC=https://rpc.tenzro.xyz

1. Find a lane

List the chains and lanes CCIP supports:

bash
tenzro ccip supported-chains --rpc $RPC
tenzro ccip lanes --rpc $RPC

Chains can be named (ethereum, arbitrum, base) or given by CCIP chain selector. Lanes are directional: a lane from A to B says nothing about B to A.

2. Quote the fee

The quote runs Router.getFee() on the source chain as a read-only call:

bash
tenzro ccip get-fee --rpc $RPC \
  --source-chain ethereum --dest-chain arbitrum \
  --receiver 0x<receiver-contract> \
  --data-hex 0x68656c6c6f
json
{
  "source_chain": "ethereum",
  "router_address": "0x...",
  "dest_chain_selector": "...",
  "fee_token": "0x0000000000000000000000000000000000000000",
  "fee_wei": "...",
  "fee_native": "..."
}

A zero fee token means the fee is paid in the source chain's native gas token. Pass --fee-token to quote in another fee token such as LINK.

3. Build the send

tenzro ccip send returns the Router.ccipSend() calldata and the value to attach. The node builds the envelope; it does not sign or broadcast it. You submit it from your own wallet on the source chain:

bash
tenzro ccip send --rpc $RPC \
  --source-chain ethereum --dest-chain arbitrum \
  --receiver 0x<receiver-contract> \
  --data-hex 0x68656c6c6f \
  --gas-limit 200000
json
{
  "status": "prepared",
  "source_chain": "ethereum",
  "router_address": "0x...",
  "dest_chain_selector": "...",
  "calldata": "0x96f4e9f9...",
  "msg_value_wei": "...",
  "gas_limit_destination": 200000
}

Send a transaction to router_address with calldata as data and msg_value_wei as value, using any wallet or library for that chain. ccipSend() returns the 32-byte message ID, which also appears in the send event in the transaction receipt. --gas-limit sets the gas available to your receiver contract on the destination chain.

4. Track delivery

bash
tenzro ccip track --rpc $RPC \
  --message-id 0x<message-id> \
  --dest-chain arbitrum \
  --offramp-address 0x<offramp-on-arbitrum>
json
{
  "message_id": "0x...",
  "dest_chain": "arbitrum",
  "offramp_address": "0x...",
  "execution_state": 2,
  "state_name": "SUCCESS",
  "description": "..."
}

Execution states are 0 untouched, 1 in progress, 2 success and 3 failure. A failure usually means your receiver reverted on the destination chain.

5. Inspect the TNZO token pools

TNZO moves over CCIP through CCT token pools: a lock-and-release pool on its home chain and burn-and-mint pools elsewhere, so the total supply stays fixed across chains. List the registered pools:

bash
tenzro cct list-pools --rpc $RPC
tenzro cct get-pool --chain base --rpc $RPC
json
{
  "chain_id": "...",
  "chain_selector": "...",
  "pool_address": "0x...",
  "token_address": "0x...",
  "pool_type": "BurnMint",
  "contract_name": "BurnMintTokenPool",
  "outbound_capacity": "...",
  "inbound_capacity": "...",
  "refill_rate": "..."
}

6. Check the rate limits

Every pool has an outbound and an inbound rate limiter per remote chain, modelled as a token bucket. Read the live state before a large transfer:

bash
tenzro ccip rate-limits --rpc $RPC \
  --chain base --pool-address 0x<pool-address> --remote-chain arbitrum

If the amount exceeds the tokens currently in the bucket, split the transfer or wait for the bucket to refill at refill_rate. You can inspect any CCT pool, not only TNZO's, with tenzro ccip token-pool --chain <chain> --pool-address <pool>.

7. Bridge TNZO over CCIP

tenzro ccip bridge routes a transfer through the node's bridge router with the CCIP adapter pinned. It moves your funds, so the request must be signed by the sending account (see RPC access). Amounts are in the smallest unit (TNZO has 18 decimals):

bash
tenzro ccip bridge --rpc $RPC \
  --source-chain base --dest-chain arbitrum \
  --asset TNZO --amount 5000000000000000000 \
  --sender 0x<your-address-on-base> \
  --recipient 0x<recipient-on-arbitrum>
json
{
  "transfer_id": "ccip-...",
  "source_chain": "base",
  "dest_chain": "arbitrum",
  "tx_hash": "0x...",
  "fee_paid": "...",
  "estimated_arrival_ms": ...,
  "adapter": "chainlink-ccip"
}

If no CCIP adapter is registered on the node, the router refuses the call rather than silently choosing another bridge. Check progress with:

bash
tenzro bridge status <transfer_id> --protocol ccip --rpc $RPC

Next steps