Skip to main content

Bridge Lane

“Bridge Lane” is QTG’s umbrella for any on-chain cross-chain movement — moving value from one EVM chain to another through a third-party messaging or transfer protocol. The lane has a separate implementation per protocol, but they all follow the same four-phase pattern.

The four-phase pattern

Every supported bridge maps onto this skeleton; what differs is who attests in phase 2 and how the destination is unlocked in phase 3.
Stargate / LayerZero is Pro (commercial), not in the OSS build. The Stargate lane and its admin surface ship only under the commercial license and are excluded from the AGPL-3.0-or-later OSS distribution. The OSS build’s LayerZero option is the FREE USDT0 native-OFT lane (exec.usdt0.send) — see LayerZero Lane.
The four-phase split is not bookkeeping — it is enforced by the executor protocol. Each phase is a node in the movement plan, dispatched and observed independently. If phase 3 succeeds but phase 4 stalls, the orchestrator can resume from phase 4 without re-burning or re-minting.

What changes between bridges

The bridges differ along three axes operators actually care about:

1. Trust anchor

  • CCTP trusts Circle. A single attestation signed by Circle’s IRIS service authorizes the mint. Centralized, fast, narrowly scoped (USDC only).
  • CCIP trusts the Chainlink DON plus an independent Risk Management Network (ARM). The protocol status field exposes the intermediate stages (committed, blessed, cursed) so observers can distinguish “DON consensus reached” from “ARM has finished its independent check.”
  • LayerZero / Stargate trusts a configurable set of DVNs (Decentralized Verifier Networks) plus an Executor role. Pool deployments are verified onchain to point at the canonical LayerZero v2 EndpointV2 address shared by all supported chains.

2. Asset scope

3. Operator gating

Every bridge has a different approved-lane mechanism that prevents a movement from being dispatched on an unaudited route:
  • CCTP — explicit destination_caller field on the burn TX. The mint can only be called by that address; QTG triple-validates signer_address == destination_caller == caller specified at burn. See CCTP Lane.
  • CCIP — admin-approved row in the CCIP lane registry keyed on (source_chain_selector, dest_chain_selector, token_address). Each row carries status, trust_tier, and registry_version; the registry version is checked for drift between prepare and submit so a registry rotation cannot silently change which router signs. See CCIP Lane.
  • Stargate (Pro) — pool registry with trust_tier (rejects unknown) and preapproval_status (rejects revoked for ERC20). Each pool’s endpoint(), eid(), and sharedDecimals() are verified onchain against the canonical LayerZero endpoint before use. See LayerZero Lane.

Idempotency: every bridge handles “submitted but not confirmed”

Bridges are the part of the system most exposed to partial failure: a transaction may be on-chain but not yet visible to the orchestrator, or a destination-side event may arrive out of order. Every bridge lane’s recover step implements the same shape: The destination-side event is the authoritative source of truth:
  • CCTP: contract reverts with "already processed" on duplicate receiveMessage() — recover interprets the revert as COMPLETED.
  • CCIP: terminal status strings (executed_success, executed_failure, cursed) come from the off-ramp; once seen, the intent never re-runs.
  • Stargate: dst-chain OFTReceived(bytes32 guid, ...) log keyed by lz_guid is the canonical “the funds landed” signal.

Pre-broadcast crash protection

All three bridges write a pre-broadcast intent row before the signing call. If the worker crashes between sign and broadcast, the next observer sees an intent in PREPARED state with no send_tx_hash and does not retry blindly — it transitions the row to a terminal *_PRE_BROADCAST_CRASH status (e.g. CCIP_PRE_BROADCAST_CRASH, STARGATE_PRE_BROADCAST_CRASH). The status change is guarded by a row-level UPDATE with expected_status, so two recovery workers competing on the same row cannot double-spend the nonce.
This guard relies on the reserved nonce being the same one used in the signed payload. The nonce is allocated under a Postgres advisory lock, then frozen into the payload hash. Any drift between the nonce in the DB and the nonce in the broadcast tx is treated as a fatal error.

Signed-recipient invariant (validated == signed)

Every on-chain send lane enforces a single fund-safety invariant: the recipient (and, where applicable, the source) re-derived from the actual signed artifact must equal the allowlist-validated authority. This closes the gap between “what the operator approved” and “what the signer actually signed” — a malicious or misconfigured prepare step cannot redirect funds to an address that passed the allowlist check only on paper. The invariant is enforced at two points:
  1. Prepare-time — intent-only resolvers pin the recipient/source from the validated intent before signing.
  2. Submit/broadcast-time — the raw signed legacy tx is RLP-decoded and the recipient/target/source re-derived from it (Gateway re-hashes the EIP-712 burn-intent digest), then compared to the validated authority.
Any mismatch is fail-closed: a fatal movement error drives the node to FAILED rather than broadcasting. Codes: SIGNED_RECIPIENT_MISMATCH, SIGNED_SOURCE_MISMATCH, SIGNED_TARGET_MISMATCH, SIGNED_TX_DECODE_FAILED, EIP712_DIGEST_MISMATCH, MISSING_PREPARED_PAYLOAD. On-chain action types split into two enforcement classes:
  • Destination-only (source is signer-bound, so only the destination is checked): stargate_send, usdt0_send, lighter_secure_withdraw.
  • Strict source + destination (both addresses checked): cctp_burn / cctp_mint, gateway_*, ccip_send, evm_erc20_transfer.
CCIP now participates in the submit-time signed-artifact invariant even though its payload is built by an out-of-process sidecar. Before the sidecar broadcasts, QTG decodes the signed legacy transaction, pins router, destination chain selector, receiver, token, amount, native fee, signer identity, and source chain id against the trusted intent, and fails closed on mismatch.

Why a sidecar for CCIP?

CCIP is the only bridge in this set whose prepare/submit/observe flow runs through an out-of-process sidecar over HTTP. The sidecar hosts the Chainlink TypeScript SDK and serves three jobs:
  1. Build a canonical ccipSend payload from the high-level intent.
  2. Decode CCIPSendRequested event logs.
  3. Poll the SDK’s message status and return a normalized status string.
This keeps the Python codebase free of the heavyweight Chainlink dependency while preserving full reconciliation power (every sidecar call returns provenance fields that QTG persists into its own intent row). CCTP and Stargate, in contrast, are pure in-process: the necessary calldata, ABI encoding, and log decoding are small enough to live inside the QTG runtime.

Observability surface

Every bridge intent surfaces the same canonical provider refs back to the movement layer:
The last_status value is the raw protocol status string (e.g. CCIP executed_success, Stargate OFT_RECEIVED), not a QTG-normalized state. The normalization happens inside the lane (status mapping for CCIP, the dst-log scanner for Stargate), so operators always have the unfiltered protocol signal available for postmortem.

Choosing a bridge

For the most-common QTG paths: The three pages below cover each lane in detail:
  • CCTP Lane — Circle’s burn-attest-mint
  • CCIP Lane — Chainlink DON + Risk Management Network
  • LayerZero Lane — Stargate v2 OFT (Pro) + USDT0 native-OFT (Free)