Canton Bridge Whitepaper

January 2026Version 0.0.1

Abstract

This paper describes a centralized bridge for ERC-20 tokens between Ethereum and Canton.

The protocol implements a lock/mint and burn/release model coordinated by an off‑chain relayer. The relayer is responsible for observing source‑chain events, enforcing finality, preventing replay, and executing the corresponding action on the destination chain.

The design goals are practical operability and correctness in the presence of real‑world failures: node/RPC outages, relayer restarts, chain reorgs, and partial execution. The system explicitly prioritizes deterministic processing, recoverability, and auditability (database + logs), while keeping the on‑chain components minimal and stable.

Design Principles

  1. Determinism over speed — prefer conservative finality windows over low latency.
  2. Fail‑safe defaults — unknown states pause processing, not continue.
  3. Recoverable by construction — every state can be advanced or retried from the database alone.
  4. Single source of truth — the database is the operational authority; chains are event sources.
  5. Minimal on‑chain logic — defer complexity to the relayer where iteration is cheap.

1 Introduction

1.1 Problem Statement

Moving assets between different chains is a complex task, which often requires usage of centralized exchanges. This complicates user onboarding to the new chains, leads to fragmented liquidity, limits possible cross-chain farming strategies, leads to less accurate pricing of on-chain assets due to smaller arbitrage options.

1.2 Scope

The protocol bridges ERC-20 between Ethereum and Canton, for example ETH on Ethereum to cETH on Canton. It is centralized by design, with a trusted relayer enforcing limits and correctness, with the future plans of making it decentralized.

In-scope:

  • EVM deposit ingestion (event scanning and reorg recovery).
  • Canton withdrawal ingestion (ledger streaming to relayer).
  • Idempotency, retries, and state tracking via a database.
  • Operational controls (timeouts, observability, manual recovery tools).

1.3 Prior Work

Bridges traditionally use lock/mint and burn/release patterns with a trusted attestation layer. The presented design follows this paradigm while focusing on deterministic backend processing, explicit checkpoints, and reorg recovery. It also borrows operational patterns from centralized settlement systems: strict state transitions, idempotency, and audit‑friendly logs.

2 Protocol Overview

2.1 Components

Ethereum (Solidity)

  • BridgeVault: holds ERC-20 token deposits and releases on withdrawal.
  • BridgeRouter: user entry point; emits Deposit and Withdraw events, enforces limits and fee policy, and manages roles.

Canton (Daml)

  • BridgeRouter: mints/burns ERC-20 tokens on Canton when called by the relayer and emits ledger events.
  • cETH (CIP‑56): wrapped asset representation on Canton with canonical token semantics.

Backend (Python Relayer)

  • EVM watcher: scans Deposit events, persists checkpoints, and triggers mint on Canton.
  • Canton watcher: streams withdraw requests and triggers finalizeWithdraw on Ethereum.
  • State store: processed_messages and chain_checkpoints ensure idempotency and recovery.
  • CLI tools: status view and manual deposit ingestion for operational recovery.

Database (Postgres)

  • processed_messages: one row per messageId, representing the bridge pipeline state and all correlation fields needed for auditing.
  • chain_checkpoints: per watcher/stream checkpoint used for resumability and reorg detection.

2.1.1 processed_messages Schema

ColumnDescription
message_idUnique cross-chain message identifier (0x hex)
statusDETECTED, PROCESSING, COMPLETED, FAILED
tx_hash_inSource chain tx hash (EVM) or contract ID (Canton)
tx_hash_outDestination chain tx hash
block_numberEVM block where deposit was found
log_indexEVM log index within block
src_input_tokenSource token address
src_input_amountAmount in base units
src_chain_idSource chain ID
dst_chain_idDestination chain ID
dst_output_tokenDestination token identifier
recipientDestination address/party
created_atRow insertion time
updated_atLast status change time

2.1.2 chain_checkpoints Schema

ColumnDescription
chainNamespace key (chain:router:dst)
keyCheckpoint type (e.g., deposit_last_processed_block)
valueBlock number or ledger offset
block_hashHash at checkpoint height (reorg detection)
updated_atLast update time

2.2 Message Model

Each transfer is identified by a unique messageId (bytes32). The relayer stores and checks this ID to prevent replay and to allow safe restarts. The messageId is carried end‑to‑end and is the primary correlation key in logs and the database.

The bridge treats a "message" as an immutable intent with an execution lifecycle. The relayer records:

  • source chain identifier and source transaction hash,
  • destination chain identifier and destination transaction hash (once executed),
  • amounts and addresses/parties,
  • timestamps for observability.

2.2.1 EVM Deposit Event (Solidity)

event Deposit(
    bytes32 messageId,
    address srcInputToken,
    uint256 srcInputAmount,
    uint256 srcChainID,
    uint256 dstChainID,
    bytes32 dstOutputToken,
    uint256 dstMinOutputAmount,
    bytes32 recipient
);

2.2.2 EVM Withdraw Event (Solidity)

event Withdraw(
    bytes32 indexed messageId,
    address indexed token,
    address indexed recipient,
    uint256 amount
);

2.2.3 Canton WithdrawEvent Template (Daml)

template WithdrawEvent
  with
    messageId      : Text         -- hex of bytes32
    token          : Text         -- canton address
    recipient      : Text         -- EVM address
    amount         : Decimal
    relayer        : Party
    auditObservers : [Party]
  where
    signatory relayer
    observer auditObservers

2.2.4 Canonical Message Fields (conceptual)

The concrete schemas differ between EVM events and Canton ledger events, but the bridge normalizes them conceptually as:

FieldTypeDescription
messageIdbytes32Unique identifier
srcChainIduint256Source chain ID
dstChainIduint256Destination chain ID
tokenaddress / TextToken address (EVM) or identifier (Canton)
senderaddress / PartySource address or party
recipientParty / addressDestination party or address
amountuint256 / DecimalAmount in base units
nonce / saltoptionalUniqueness aid
metadataoptionalAdditional Reference data

2.3 Trust Model

The relayer is trusted to:

  • execute mint/burn and withdrawals correctly,
  • enforce limits and validation rules,
  • respect finality and reorg safety.

Users trust that the relayer will not mint unbacked assets and will not release funds without a valid Canton withdrawal. Operational controls, audit logs, and DB state transitions provide accountability.

In practice, this implies:

  • The relayer's key management and operational procedures are part of the security boundary.
  • The bridge is only as reliable as its RPC/data sources unless the relayer cross‑checks providers.

2.4 State Machine

The relayer uses a small set of statuses in processed_messages to drive idempotent processing.

StatusMeaningTypical Next Step
DETECTEDSource event observed and validated; not yet executed on destinationExecute destination action
PROCESSINGDestination action submitted or in-flightWait receipt/finality or retry
COMPLETEDDestination action confirmed and finalizedNo further action
FAILEDTerminal failure requiring operator actionManual retry / fix / cancel

The state machine is intentionally simple. It can be extended later with finer granularity (e.g., SUBMITTED, MINED, FINALIZED) if operational requirements demand it.

                    ┌─────────────────────┐
                    │      DETECTED       │
                    │  (event ingested)   │
                    └──────────┬──────────┘
                               │
                      submit destination action
                               │
                               ▼
                    ┌─────────────────────┐
          ┌─────────│     PROCESSING      │─────────┐
          │         │   (tx in‑flight)    │         │
          │         └──────────┬──────────┘         │
          │                    │                    │
    tx reverted /        receipt + finality   unrecoverable
    timeout/nonce error        │              error
          │                    │                    │
          │                    ▼                    │
          │         ┌─────────────────────┐         │
          │         │     COMPLETED       │         │
          │         │    (finalized)      │         │
          │         └─────────────────────┘         │
          │                                         │
          └────────────────────┬────────────────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │       FAILED        │
                    │ (operator action)   │
                    └─────────────────────┘

3 Protocol Flows

3.1 EVM → Canton (Lock/Mint)

  1. User calls BridgeRouter.deposit on Ethereum.
  2. Deposit event is emitted.
  3. EVM watcher scans logs up to a safe head (latest − confirmations).
  4. Message is validated against limits and policy (min amount, daily caps, destination checks).
  5. Message is stored in DB as DETECTED.
  6. Relayer calls Canton BridgeRouter.mint.
  7. DB status transitions: DETECTEDPROCESSINGCOMPLETED or FAILED.
┌───────────────────────────────────────────────────────────────────────┐
│                        EVM → Canton (Lock / Mint)                     │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│   User                 Ethereum                    Backend            │
│    │                      │                           │               │
│    │── deposit() ────────►│                           │               │
│    │                      │── Deposit event ─────────►│               │
│    │                      │                           │               │
│    │                      │   (wait confirmations)    │               │
│    │                      │                           │               │
│    │                      │                 ┌─────────┴─────────┐     │
│    │                      │                 │ validate & insert │     │
│    │                      │                 │ processed_messages│     │
│    │                      │                 │ status = DETECTED │     │
│    │                      │                 └─────────┬─────────┘     │
│    │                      │                           │               │
│    │                      │                           ▼               │
│    │                      │                 ┌──────────────────────┐  │
│    │                      │                 │  Canton JSON API     │  │
│    │                      │                 │  create / exercise   │  │
│    │                      │                 │  mint on BridgeRouter│  │
│    │                      │                 └─────────┬────────────┘  │
│    │                      │                           │               │
│    │                      │                   status = COMPLETED      │
│    │                      │                           │               │
└───────────────────────────────────────────────────────────────────────┘

3.1.1 Validation Checklist

  • Event authenticity: emitted by the configured BridgeRouter address.
  • Token correctness: the deposited token is the expected ETH/cETH contract.
  • Amount bounds: amount >= minAmount and amount <= maxPerTx.
  • Rate limits: daily limit per token and/or per user.
  • Destination validity: destination chain and recipient party/address allowed.

3.1.2 Failure Modes

  • RPC errors during scan: handled via retries, scan is resumable.
  • Canton RPC/ledger submission fails: message remains DETECTED or transitions to FAILED with error.
  • Relayer crash after submission: message is recovered via DB state (retries should be safe and idempotent).

3.2 Canton → EVM (Burn/Release)

  1. Canton emits DepositEvent with message data.
  2. Canton watcher stores and marks as DETECTED, then immediately PROCESSING.
  3. Relayer calls Ethereum finalizeWithdraw via EVMSigner.
  4. Receipt is awaited; finality wait is enforced (EVM_TX_CONFIRMATIONS blocks).
  5. DB status transitions to COMPLETED or FAILED.
┌───────────────────────────────────────────────────────────────────────┐
│                       Canton → EVM (Burn / Release)                   │
├───────────────────────────────────────────────────────────────────────┤
│                                                                       │
│   Canton Ledger            Backend                    Ethereum        │
│        │                      │                          │            │
│        │── DepositEvent ─────►│                          │            │
│        │   (websocket)        │                          │            │
│        │                      │                          │            │
│        │            ┌─────────┴─────────┐                │            │
│        │            │ insert message    │                │            │
│        │            │ status = DETECTED │                │            │
│        │            │     → PROCESSING  │                │            │
│        │            └─────────┬─────────┘                │            │
│        │                      │                          │            │
│        │                      │── finalizeWithdraw() ───►│            │
│        │                      │                          │            │
│        │                      │     (wait receipt)       │            │
│        │                      │     (wait finality)      │            │
│        │                      │                          │            │
│        │                      │◄─── receipt + conf ──────│            │
│        │                      │                          │            │
│        │            status = COMPLETED                   │            │
│        │                      │                          │            │
└───────────────────────────────────────────────────────────────────────┘

3.2.1 Failure Modes

  • Canton stream interruption: resumable from checkpoint; backlog catch‑up.
  • Ethereum tx underpriced/stuck: processing monitor alerts; operator can replace tx.
  • Ethereum reorg after inclusion but before finality: relayer continues waiting until confirmations are re‑achieved or re-submits if needed.

3.3 Exactly-Once vs At-Least-Once

The relayer processes external events at-least-once (events can be re-observed after restart or rollback), but the combined design aims for exactly-once effects by enforcing idempotency at the message level:

  • source observation can repeat,
  • destination execution is guarded by messageId uniqueness and DB state.

The system therefore provides "exactly-once per messageId" semantics, assuming correct DB operation and consistent messageId derivation.

4 State, Finality, and Reorgs

4.1 Checkpointing

chain_checkpoints stores the last fully scanned block and its block hash. On restart, the watcher resumes from this checkpoint. Checkpoints are namespaced by chain ID, router address, and destination chain to prevent collisions across networks.

Checkpointing serves two distinct purposes:

  • Progress: resume scanning without rescanning from genesis.
  • Integrity: detect when a previously "processed" block has changed due to reorg.

4.2 Reorg Detection and Recovery

The watcher compares the stored checkpoint hash with the current chain hash at the same height. A mismatch triggers rollback by a safety buffer, deletes affected rows, and rescans the range. This ensures that deposits from reorged blocks are not treated as finalized.

The rollback strategy is conservative:

  • Roll back to a block before the divergence by a fixed buffer.
  • Delete any processed_messages derived from blocks above the rollback height.
  • Rescan deterministically from the rollback height to the safe head.
  • Execute Bridge transaction on the destination chain with the updated state.

This approach intentionally prefers correctness over speed.

4.3 Idempotency

processed_messages ensures each messageId is processed once, supporting safe retries and relayer restarts. The DB is the source of truth for operational state and auditing.

Idempotency is implemented as a uniqueness constraint at the application level. The relayer always queries/updates by messageId and treats duplicates as no‑ops.

4.4 Finality Policy

The relayer separates inclusion from finality:

  • Inclusion: tx is mined and has a receipt.
  • Finality: tx has reached a configured confirmation depth.

For EVM deposits, the watcher only scans up to latest − confirmations. For EVM withdrawals, the signer waits for the receipt and then waits until the receipt's block has enough confirmations.

5 Reliability Controls

  • Confirmations: avoid processing near‑head blocks.
  • Exit checkpointing: resumable processing on shutdown.
  • Catch‑up mode: skips waiting time between block creation reach latest block quickly.

5.1 Configuration Parameters

Operators should treat the following as explicit "risk knobs":

ParameterPurposeRisk if Too LowRisk if Too High
confirmationsReorg safety depthProcess reorged eventsIncreased latency
rollback_bufferHow far to roll back on reorgMiss divergence edgesSlower recovery
max_chunk_sizeeth_getLogs chunkingRPC failures/timeoutsMore RPC calls
processing timeoutAlert threshold for stuck messagesAlert fatigueSlow detection

These should be tuned per chain and provider characteristics.

6 Security Considerations

  • The relayer is a single point of control; access and key management are critical.
  • RPC integrity is required; using multiple providers is recommended.
  • Database integrity is required for auditability and recovery.
  • Operational access should be limited, monitored, and rotated.

6.1 Threat Model (Centralized)

This system should be analyzed as a centralized custody/settlement component:

  • A compromised relayer key can steal funds.
  • A compromised RPC provider can cause incorrect observations or delayed processing.
  • A compromised database can hide or distort operational history.

6.1.1 Attack Surface Summary

ComponentAsset at RiskAttack VectorImpact
Relayer EOA keyVault fundsKey theftTotal loss of funds is prevented by the daily limits on the contract
RPC providerCorrect observationsMan‑in‑the‑middle / eclipseDouble‑spend - prevented by the contract validation, missed deposits - can be added to the system manually
DatabaseAudit trailSQL injection / credential leakAltered history - the history could be rescanned, double processing - prevented by the contract validation
Canton JSON APIMint/burnToken hijack / unauthorized exerciseUnbacked mint
Process/hostAllRCE / container escapeFull compromise

6.2 Practical Mitigations

  • Hardware-backed key storage and strict operational procedures.
  • Multiple independent RPC providers; compare results at critical boundaries.
  • Strict allow‑lists and rate limits.
  • Run relayer in isolated network environment.
  • On-chain validation which prohibits transaction replay.