tesseract

Architecture

Commit. Reveal. Resolve or refund.

A Tesseract swap group is a cross-chain intent settled through a three-phase lifecycle enforced entirely by Vyper contracts on each rollup. An agent submits one intent and gets an all-or-nothing outcome; the Rust relayer only submits transactions — it can never authorise a resolution the contracts do not already permit.

01 TesseractBuffer.vy

Commit

A user submits keccak(payload ‖ secret) — a hash commitment — for each leg, along with a tx id, deadline, a shared swap_group_id, and a refund recipient. Searchers and sequencers reading the mempool see only opaque bytes. There is nothing to front-run.

02 TesseractBuffer.vy

Reveal

One block after the commitment lands, the user reveals the plaintext payload and secret. The contract verifies keccak(payload ‖ secret) == commitment. By now the block ordering that would have enabled a sandwich is already settled, so the reveal is safe to make public.

03 AtomicSwapCoordinator.vy

Resolve or refund

After the minimum resolution delay (default 2 blocks), an authorised resolver finalises every leg of the group. Group atomicity is enforced by the swap_group_id: all legs resolve, or — if any leg misses its deadline — every leg becomes refundable on its own chain. There is no stuck-mid-flight state.

Topology

One relayer, many rollups, no shared vault.

Each rollup runs its own copy of the seven Vyper contracts and holds its own native assets. The Rust relayer watches all of them in parallel and coordinates resolution — but funds never leave their home chain until the atomic group resolves.

   Arbitrum                 Optimism                   Base
 ┌───────────────┐       ┌───────────────┐        ┌───────────────┐
 │ TesseractBuffer│      │ TesseractBuffer│       │ TesseractBuffer│
 │ Coordinator    │      │ Coordinator    │       │ Coordinator    │
 │ (native assets)│      │ (native assets)│       │ (native assets)│
 └───────┬───────┘       └───────┬───────┘        └───────┬───────┘
         │  events / commits     │                        │
         └───────────┬───────────┴───────────┬────────────┘
                     ▼                        ▼
             ┌───────────────────────────────────────┐
             │        Rust relayer (no authority)     │
             │  WebSocket + HTTP failover · Postgres  │
             │  submits txs · cannot authorise resolve│
             └───────────────────────────────────────┘

   swap_group_id binds every leg → resolve everywhere OR refund everywhere

In code

The commit path, in Vyper.

A representative sketch of the buffer's commit entrypoint. The commitment is stored as an opaque hash; nothing about the trade is legible until the reveal.

TesseractBuffer.vy — commit
# @version ^0.3.10

MIN_RESOLUTION_DELAY: constant(uint256) = 2  # blocks

@external
def buffer_transaction_with_commitment(
    tx_id: bytes32,
    commitment: bytes32,        # keccak(payload || secret)
    swap_group_id: bytes32,
    deadline: uint256,
    refund_to: address,
):
    assert self.has_role(BUFFER_ROLE, msg.sender)
    assert deadline > block.timestamp, "past deadline"
    self.commitments[tx_id] = Commit({
        hash: commitment,
        group: swap_group_id,
        reveal_block: block.number + 1,
        deadline: deadline,
        refund_to: refund_to,
    })
    log Committed(tx_id, swap_group_id, deadline)
TesseractBuffer.vy — reveal + resolve gate
@external
def reveal_transaction(
    tx_id: bytes32,
    payload: Bytes[512],
    secret: bytes32,
):
    c: Commit = self.commitments[tx_id]
    assert block.number >= c.reveal_block, "too early"
    assert keccak256(concat(payload, secret)) == c.hash
    self.revealed[tx_id] = payload

@external
def resolve_dependency(tx_id: bytes32):
    assert self.has_role(RESOLVE_ROLE, msg.sender)
    c: Commit = self.commitments[tx_id]
    # flash loans cannot span the resolution delay
    assert block.number >= c.reveal_block + MIN_RESOLUTION_DELAY
    assert block.timestamp <= c.deadline, "expired -> refundable"
    self._resolve_group(c.group, tx_id)

Illustrative for readability — see the canonical source in the open-source repository. Function names, roles, and the 2-block resolution delay match the shipped contracts.

Why it holds

Three security properties, all structural.

Commit-reveal MEV protection

The payload is a hash until after it is on-chain. A searcher sees opaque bytes, and by reveal time block ordering is already fixed — the sandwich window never opens.

Flash-loan resistance

Resolution requires the reveal block plus a minimum delay (default 2 blocks). A flash loan cannot span two blocks, so single-block flash-loan exploits are impossible — not mitigated, impossible.

Group atomicity

Every leg shares a swap_group_id. All legs resolve within the deadline, or all become refundable. A 3-way swap across three rollups is one operation, not three failure modes.

Run it yourself in fifteen minutes.

The quickstart walks you through running the relayer and creating your first atomic swap group on testnet.