Skip to main content

Cross-chain bridges

A bridge moves value or messages between chains. The hardest engineering question is: how does chain A know that something happened on chain B?

Trusted-validator models put that responsibility on a small federation. Light- client models put it on cryptographic state proofs. Optimistic oracle models put it on an economic game — anyone can claim "this transaction confirmed on chain B", and unless someone disputes within a window, the claim is accepted.

OMY's optimistic oracle is well-suited for this. The bridge consumer asks "did tx 0xabc...123 finalize on chain X by block Y?"; an asserter proposes yes or no; the bridge releases (or refunds) on the oracle's answer.

The integration shape

User → bridge contract on TON

│ deposits USDT, requests withdrawal to chain X


Bridge state: PendingWithdraw

│ user (or relayer) executes the matching tx on chain X


Bridge.RequestAttestation → OMY
│ (question: "did tx 0xabc on chain X confirm at block ≥ Y?")


OMY Assertion lifecycle
│ (propose YES with bond, no dispute, finalize)


Bridge ◄── OracleResult{questionId, answer=true}


Bridge.Settle — releases funds / acknowledges receipt

The bridge contract pays the oracle's bond from its own treasury (recoverable on resolution). The proposer can be a relayer bot that watches for finalized remote txs and proposes YES with a small bond. The dispute path catches anyone who tries to claim a fake confirmation.

Why optimistic vs light client

OptimisticLight client
VerifiesEconomic incentives via bondCryptographic state proof
Cost per query~$0 in common caseHigh (proof verification gas)
Sub-block freshnessNo (liveness window)Yes
Works for chains without verifiable proofsYesNo
Setup costOne contract, two rolesCustom per-chain proof verifier

Optimistic is the right model when the chain you're bridging from is hard to prove (non-EVM, custom consensus) or when query volume is low enough that the light-client overhead isn't worth it.

For pure EVM-to-EVM with high query volume, a light client may win on cost. OMY is the better fit when:

  • You're bridging from / to TON (no production light client for TON in either direction yet)
  • You're bridging from a chain where proofs are expensive (e.g., zk-rollups with proof-aggregation latency)
  • You're bridging arbitrary messages, not just token balance changes

Bond sizing for bridges

Bonds should be sized to the largest single payout the attacker could extract from a successful lie, not to TVL average. A bridge moving $1M quickly per day with $10M TVL still needs a bond large enough to deter someone from stealing $1M in a single attack.

A conservative formula:

bond = max(min_bond, 10% × max_single_withdrawal)

For a bridge with max_single_withdrawal = 100 000 USDT, bond = 10 000 USDT (at the cap). This is the upper end of OMY's MAX_BOND_CAP — beyond which security has to come from the resolver, not the bond.

Anti-spoof on the result

This matters more for bridges than any other use case. The bridge contract must verify the OracleResult came from the assertion it bound, not just any contract claiming to be one:

OracleResult => {
assert (in.senderAddress == state.boundAssertion!) throw Err.NotOurOracle;
// safe to settle
}

Without this check, an attacker deploys their own contract with the same opcode + body shape, points it at the bridge, and triggers a fake "confirmed" result. Same defense applies to your AssertionCreated callback — verify the sender is the OracleFactory you registered.

What about bridges going INTO TON?

The flow is symmetric. A remote chain's bridge attests "X USDT was locked at this address on chain B"; OMY verifies it; the TON-side bridge mints the wrapped representation. Same lifecycle, same dispute path.

Integration checklist

import {DocFeatures, DocFeature} from '@site/src/components/docs/DocFeatures';

Verify sender == boundAssertion. The single most important bridge check. Not just TVL. A bridge can be attacked by extracting one large payout. Include tx hash, exact block number, exact amount. Never paraphrase. If chain B has 12-block finality (~3 min on Ethereum), liveness ≥ 30 min. Account for re-orgs. If the assertion goes Cancelled (timeout), refund the bridge user. Don't strand their deposit. Pay the proposer a small fee from the bridge's revenue. Otherwise the happy path stalls.