Tenzro Testnet is live —request testnet TNZO
← Back to Tutorials

Transfer TNZO Cross-Chain via CCT

BridgeIntermediate25 min

Chainlink CCT (Cross-Chain Token) v1.6+ is a pool-based standard for moving the same token across multiple chains over CCIP. TNZO is deployed as a CCT across Ethereum, Base, Arbitrum, Optimism, and Solana. This tutorial covers the pool registry, CCIP fee quoting, and actually submitting a transfer.

What You'll Build

  • Inspect the TNZO CCT pool registry
  • Quote a CCIP fee from Ethereum to Base
  • Send 100 TNZO cross-chain with ccip_send_message
  • Track the message via ccip_track_message

Pool Model

LockRelease (canonical chain)
  outbound: ERC-20 transferFrom(user, pool)  pool holds tokens
  inbound:  pool transfer(to, amount)        pool releases tokens

BurnMint (remote chains)
  outbound: pool.burn(from, amount)          supply decreases
  inbound:  pool.mint(to, amount)            supply increases

Invariant: sum(locked on canonical) == sum(minted on all remotes)

Step 1: List the Pools

tenzro_cctListPools()
  -> [
    { chain: "ethereum",  pool_type: "LockRelease", pool_address: "0x...", token_address: "0x...", ccip_router: "0x...", rmn_proxy: "0x..." },
    { chain: "base",      pool_type: "BurnMint",    pool_address: "0x...", token_address: "0x...", ccip_router: "0x...", rmn_proxy: "0x..." },
    { chain: "arbitrum",  pool_type: "BurnMint",    pool_address: "0x...", token_address: "0x...", ccip_router: "0x...", rmn_proxy: "0x..." },
    { chain: "optimism",  pool_type: "BurnMint",    pool_address: "0x...", token_address: "0x...", ccip_router: "0x...", rmn_proxy: "0x..." },
    { chain: "solana",    pool_type: "BurnMint",    pool_address: "...",    token_address: "...",    ccip_router: "...",    rmn_proxy: "..." }
  ]

Step 2: Look Up a Specific Pool

tenzro_cctGetPool({ "chain": "base" })
  -> {
    chain: "base",
    pool_type: "BurnMint",
    pool_address:  "0x...",
    token_address: "0x...",
    ccip_router:   "0x...",
    rmn_proxy:     "0x..."
  }

Step 3: Quote the CCIP Fee

Fees are denominated in LINK or native gas. The quote is a real Router.getFee() eth_call under the hood:

ccip_get_fee({
  "source_chain": "ethereum",
  "dest_chain":   "base",
  "token":        "TNZO",
  "amount":       "100.0"
})
  -> { fee: "0.02 LINK", fee_token: "LINK", source_router: "0x..." }

Step 4: Send the Message

CCIP encodes the transfer as a Router.ccipSend() call. On the source chain the pool locks/burns; the CCIP OCR DON and RMN independently sign; the destination pool unlocks/mints on finalization:

ccip_send_message({
  "source_chain": "ethereum",
  "dest_chain":   "base",
  "receiver":     "0xRecipientOnBase...",
  "token":        "TNZO",
  "amount":       "100.0",
  "fee_token":    "LINK"
})
  -> { tx_hash: "0x...", message_id: "0x..." }

Step 5: Track the Message

ccip_track_message({ "message_id": "0x..." })
  -> {
    state: "Success",  // InProgress | Success | Failure
    source_tx: "0x...",
    dest_tx:   "0x...",
    dest_chain: "base"
  }

CLI

# List all TNZO CCT pools
tenzro cct list

# Look up a specific chain's pool
tenzro cct pool --chain base

# Quote and send via the chainlink MCP tools
tenzro chainlink ccip-get-fee --source ethereum --dest base --token TNZO --amount 100
tenzro chainlink ccip-send    --source ethereum --dest base --token TNZO --amount 100 --receiver 0x...

TypeScript SDK

import { TenzroClient } from "@tenzro/sdk";

const client = new TenzroClient();

// 1. Pick a destination pool
const pool = await client.cct.getPool({ chain: "base" });
console.log("dst pool:", pool.pool_address, "type:", pool.pool_type);

// 2. Quote the CCIP fee
const fee = await client.chainlink.ccipGetFee({
  source_chain: "ethereum",
  dest_chain:   "base",
  token:        "TNZO",
  amount:       "100.0",
});

// 3. Build and submit the CCIP message
const res = await client.chainlink.ccipSend({
  source_chain: "ethereum",
  dest_chain:   "base",
  token:        "TNZO",
  amount:       "100.0",
  receiver:     "0xRecipientOnBase...",
  fee_token:    "LINK",
});
console.log("tx", res.tx_hash, "message", res.message_id);

RMN defense-in-depth. Each pool references an RMN proxy — an independent "second opinion" committee on CCIP messages. A transfer only executes when the primary DON and the RMN both sign, so a compromise of one committee doesn't directly forge transfers.

CCT vs Cross-VM Pointer Model

Within the Tenzro ledger itself, TNZO uses a Sei-V2-style pointer model (wTNZO ERC-20 pointer, SPL adapter, CIP-56 DAML holding) — notCCT — because all VMs share the same native balance and there is no cross-chain risk. CCT+CCIP is reserved for true external chains where a lock/mint bridge is required.

What You Learned

Next Steps