Bridge TNZO via Wormhole
The Tenzro Wormhole adapter uses the Guardian network — a 19-node set that signs cross-chain VAAs (Verifiable Action Approvals)— to move TNZO and arbitrary messages between 30+ chains. This tutorial walks through chain-ID resolution, VAA parsing, and submitting a real bridge transfer.
What You'll Build
- Resolve human-readable chain names to Wormhole uint16 IDs
- Parse a VAA identifier into
{emitter_chain, emitter_address, sequence} - Initiate a TNZO bridge from Tenzro to Solana
- Call the flow from the CLI, Rust SDK, and TypeScript SDK
Understanding VAAs
A VAA is a signed payload (chain, emitter, sequence, timestamp, nonce, consistency, payload). A message is considered finalized once at least 13 of 19 Guardians have signed. Destination chains reject VAAs whose signatures don't verify against the current Guardian set.
source chain Guardians (off-chain) destination chain
------------ ----------------------- -----------------
emit message ─────────► observe (finality)
sign (13/19 needed)
publish VAA
─────────► submit VAA
verify signatures
mint/unlock tokensStep 1: Resolve Chain IDs
Wormhole uses uint16 chain IDs that differ from the EVM chainId. Tenzro exposes a translator:
tenzro_wormholeChainId({ "chain": "ethereum" })
-> { chain: "ethereum", wormhole_chain_id: 2 }
tenzro_wormholeChainId({ "chain": "solana" })
-> { chain: "solana", wormhole_chain_id: 1 }
tenzro_wormholeChainId({ "chain": "base" })
-> { chain: "base", wormhole_chain_id: 30 }Step 2: Parse a VAA Identifier
VAA IDs are canonically written as <chain_id>/<emitter_address>/<sequence>:
tenzro_wormholeParseVaaId({ "vaa_id": "2/0x3ee18b2.../42" })
-> {
emitter_chain: 2,
emitter_address: "0x3ee18b2...",
sequence: 42
}This is what you pass to a Wormhole explorer or an off-chain relayer to look up the signed VAA payload once Guardians have published it.
Step 3: Bridge TNZO
The bridge entry point locks TNZO on Tenzro (via the Wormhole Token Bridge integration) and posts a transfer message to the Core Bridge. Guardians observe, sign a VAA, and a relayer redeems it on the destination chain:
tenzro_wormholeBridge({
"token": "TNZO",
"from_chain": "tenzro",
"to_chain": "solana",
"amount": "100.0",
"sender": "0xSenderOnTenzro...",
"recipient": "SolanaPublicKey..."
})
-> {
tx_hash: "0x...",
wormhole_message_id: "...",
estimated_finality_sec: 900
}Step 4: CLI
# Resolve a chain ID
tenzro wormhole chain-id --chain ethereum
# Parse a VAA identifier
tenzro wormhole parse-vaa --vaa-id 2/0x3ee18b2.../42
# Bridge TNZO from Tenzro to Solana
tenzro wormhole bridge \
--token TNZO \
--from-chain tenzro \
--to-chain solana \
--amount 100.0 \
--recipient SolanaPublicKey...Step 5: Rust SDK
use tenzro_sdk::TenzroClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = TenzroClient::connect(Default::default()).await?;
// 1. Resolve Wormhole chain IDs
let from = client.wormhole().chain_id("tenzro").await?;
let to = client.wormhole().chain_id("solana").await?;
println!("src={} dst={}", from.wormhole_chain_id, to.wormhole_chain_id);
// 2. Initiate bridge
let res = client.wormhole().bridge(
"TNZO", "tenzro", "solana",
"100.0",
"0xSenderOnTenzro...",
"SolanaPublicKey...",
).await?;
println!("source tx: {}", res.tx_hash);
println!("message: {}", res.wormhole_message_id);
println!("wait ~{}s for Guardian finality", res.estimated_finality_sec);
Ok(())
}Step 6: TypeScript SDK
import { TenzroClient } from "@tenzro/sdk";
const client = new TenzroClient();
const res = await client.wormhole.bridge({
token: "TNZO",
fromChain: "tenzro",
toChain: "base",
amount: "25.5",
sender: "0xSenderOnTenzro...",
recipient: "0xRecipientOnBase...",
});
console.log("bridge tx", res.tx_hash);Trust model. Wormhole assumes an honest majority of its 19 Guardians. If you need a distinct trust domain, the CCT / Chainlink CCIP and LayerZero V2 adapters give you different DON/DVN committees — use them in parallel for independent attestations when risk tolerance is low.
What You Learned
- VAA basics — emitter/sequence layout and Guardian finality
- Chain-ID mapping — Wormhole's uint16 IDs vs EVM chain IDs
- Bridge call —
tenzro_wormholeBridgefrom CLI, Rust, and TypeScript - Parallel adapters — when to pair Wormhole with CCIP/LayerZero for redundancy
Next Steps
- See the CCT Transfers tutorial for Chainlink CCIP-based TNZO bridging
- See the LI.FI Aggregation tutorial to route across multiple bridges automatically
- Read the Wormhole reference docs