# Introducing fast-fill: instant cross-chain transfers on the bridge you already trust

> A thin optimistic-fill layer on Circle CCTP v2 and LayerZero OFT: funds in seconds when a relayer fronts them, and never worse than the bridge if no one does. No escrow, no liquidity pool, no new trust assumption. Proven on mainnet.

- Canonical URL: https://blog.eggtech.io/posts/announcing-fast-fill
- Markdown URL: https://blog.eggtech.io/posts/announcing-fast-fill/index.md
- Published: 2026-07-01
- Updated: 2026-07-01
- Author: Kai Aldag
- Reading time: 25 min read
- Tags: crypto, cross-chain, systems

## Referenced Links

- [Live demo](https://fast-fill.vercel.app)
- [GitHub](https://github.com/KaiCode2/fast-fill)
- [Architecture](https://github.com/KaiCode2/fast-fill/blob/main/docs/ARCHITECTURE.md)

---

<LogoBanner src="/images/announcing-fast-fill/fastfill-logo.png" alt="Fast Fill" />

## TL;DR

Canonical, message-based bridges — Circle's **CCTP** and LayerZero's **OFT** — are the safest way to move assets across chains, because the destination only ever mints against a cryptographically verified message. The catch is **latency**: you wait for source-chain finality and off-chain attestation before the funds appear. That's seconds in the best case and many minutes in the worst.

The usual fix — a "fast bridge" with its own liquidity pools, escrow contracts, and solver inventory — buys speed by adding a whole new system to trust, and can leave you *worse off* than the bridge if it fails.

**fast-fill takes a different route.** It rides the bridge's own authenticated channel and lets an external relayer *pre-pay* your transfer on the destination chain **before** the bridge message is verified, for a small, user-priced premium. When the bridge finally settles, the in-flight bridged funds reimburse the relayer. The relayer never holds your money in escrow; the transfer either arrives early (a relayer filled it) or on time (the bridge delivers it) — never late, never for more than you agreed.

- ⚡ **Best case:** funds in ~1.5 seconds.
- 🛟 **Worst case:** identical to using the bridge directly — same arrival time, zero premium.
- 🔒 **No escrow, no pool:** the bridged funds *are* the relayer's reimbursement.
- 🧾 **Trustless & permissionless filling:** a relayer that fills a fake order can only lose its *own* money.
- ✅ **Live on mainnet:** real USDC and real Circle attestations — the headline optimistic fill proven on Base → Arbitrum, with the executor-routed path live across Base, Optimism, and Arbitrum.

This post goes deep: the problem, the mechanism, the economics (with numbers), the security model, and the mainnet transaction record.

---

## The problem: you shouldn't have to choose between *fast* and *trustless*

Moving a dollar of USDC from Base to Arbitrum sounds simple. Under the hood, a canonical bridge does something careful:

1. **Burn** (or lock) the token on the source chain.
2. Wait for the source chain to reach a **finality threshold** so the burn can't be reorged away.
3. An off-chain **attestation service** (Circle's Iris for CCTP, the DVN set for LayerZero) signs off on the message.
4. Someone submits the verified message on the destination, which **mints** (or unlocks) the token.

Every step of that is what makes it *safe* — the destination mints only against a message it can cryptographically verify. But steps 2 and 3 are also why it's *slow*. Depending on the route and the finality mode you pick, "slow" ranges from ~15 seconds to well over ten minutes.

The industry's answer has been the **fast bridge / intent-solver** model: liquidity providers pre-position inventory on every chain, an escrow contract holds your input, and a solver network competes to front you the output. It's fast — but look at what you took on:

- A **new liquidity pool** to trust (and to be drained if there's a bug).
- An **escrow contract** holding your funds mid-flight.
- A **solver's promise** — and a failure mode where a solver front-runs, grief-fails, or vanishes, potentially leaving you worse off than if you'd just used the bridge.

The insight behind fast-fill is that **you don't need any of that** to go fast. The canonical bridge is *already* delivering your funds to the destination — reliably, on its own authenticated rails. All that's missing is someone willing to advance you the money for the few seconds or minutes until it lands. If you can pay that person a small premium **and** make it impossible for them to steal or strand your funds, you get bridge-grade safety at solver-grade speed.

---

## The idea: an optimistic fill on the bridge's own rails

Here is the entire mechanism in one sequence. The user initiates a normal bridge transfer, but the destination recipient is set to the fast-fill **adapter**, and the transfer's `hookData` (CCTP) or `composeMsg` (OFT) carries an encoded **Order**. A relayer watching for `OrderCreated` events can then fill the order on the destination *before* the bridge verifies anything.

```mermaid
sequenceDiagram
    actor U as User
    participant S as SourceAdapter
    participant B as Bridge
    actor R as Relayer
    participant D as DestAdapter
    actor C as Recipient

    U->>S: initiate — pull funds, encode Order in hook
    S->>B: burn / send, recipient = DestAdapter
    S-->>R: emit OrderCreated
    Note over R,C: BEFORE the bridge verifies
    R->>D: fill(order)
    D->>C: pay outputAmount minus fee  [instant]
    Note over D: record filler = Relayer
    B->>D: message verified, funds delivered
    D->>R: reimburse outputAmount  (else recipient, if unfilled)
    D->>C: pay surplus
```

The two outcomes are worth stating precisely, because the *worst* case is the whole point:

- **Best case (a relayer fills):** the recipient is paid `outputAmount − fee` in seconds. When the bridge message later settles, the arrived funds reimburse the relayer exactly `outputAmount`, and any surplus goes to the recipient.
- **Worst case (no one fills):** the bridge settles as it always would, and the recipient receives the full arrived amount — at the same time, and for the same cost, as if fast-fill weren't in the path at all.

There is no third outcome where the user is late *and* out-of-pocket. fast-fill can only make a transfer faster or leave it unchanged.

---

## The load-bearing invariant: why filling is trustless

Everything rests on one line:

```
orderId = keccak256(abi.encode(order))
```

The **same** `orderId` is computed in three places: when the source encodes the order into the bridge payload, when a relayer fills, and when the destination settles the authenticated message.

```mermaid
flowchart LR
    A["source: encode Order<br/>into hookData / composeMsg"] --> B["relayer: fill(order)<br/>recompute orderId"]
    A --> C["destination: settle decodes the<br/>authenticated Order, recompute orderId"]
    B -. "must match" .-> C
```

Because the order data settles through the **bridge's authenticated channel** — a Circle-attested message or a LayerZero-verified compose — a relayer that fills against a *fabricated* order computes an `orderId` that no settling message will ever reproduce. That relayer is simply **never reimbursed**.

This flips the usual trust model on its head. **A careless or malicious filler can only ever lose its own funds** — never the recipient's, never the protocol's, never another filler's. There is nothing to steal by filling a bogus order; you'd just be gifting money to a stranger. That's exactly why fast-fill makes filling **permissionless by default**: there's no allowlist, no staking, no reputation system, because the economics are self-punishing.

---

## How it works, mechanically

### The Order

An order is a plain struct, encoded verbatim into the bridge's hook payload. Transport identifiers (CCTP domains, LayerZero endpoint ids) are deliberately *not* in it — they're resolved at the contract edges — so the `orderId` stays stable and a relayer only needs the emitted order to reconstruct the hash.

```solidity
struct Order {
    uint8   bridgeType;           // 0 = CCTP, 1 = OFT
    uint32  srcChainId;
    uint32  dstChainId;
    bytes32 sender;               // user on the source chain
    bytes32 recipient;            // final recipient (canonical address.toBytes32())
    bytes32 inputToken;           // pulled from the user on the source
    bytes32 outputToken;          // delivered on the destination
    uint256 inputAmount;          // pulled from the user (pre bridge fee)
    uint256 outputAmount;         // deterministic worst-case arriving amount the filler is owed
    uint64  nonce;                // per-source-adapter monotonic counter
    uint64  startTime;            // absolute source timestamp — pricing baseline
    uint64  expectedDeliveryTime; // premium decays to 0 at/after this point
    uint256 discountRate;         // WAD/second — user-chosen time-premium accrual
    uint256 baseFee;              // flat fee (output-token units) owed on any fill
    uint64  callbackGasLimit;     // gas forwarded to the recipient's onFastFill hook
    bytes   hookData;             // optional destination-execution payload
}
```

### The order lifecycle

Every order moves through a single-slot status machine. The record packs into one storage slot (`address filler; FillStatus status; uint40 fillTime`), so the hot path is cheap.

```mermaid
stateDiagram-v2
    [*] --> None
    None --> Filled: fill() — relayer fronts payout to recipient
    None --> Settled: settle() with no fill — recipient gets everything
    Filled --> Settled: settle() — filler reimbursed, surplus to recipient
    Settled --> [*]
```

- `fill` requires `status == None` (rejects double-fills and fill-after-settle).
- `settle` requires `status != Settled` — the bridge's own nonce is the first, independent replay guard; this is defense-in-depth.
- `Settled` is terminal. The destination contract's balance is the reimbursement pool, and every order settles exactly once.

### Settlement authentication

The subtle part is making sure that *only* a genuine, bridge-verified message can settle an order — and that nobody can forge a burn to our adapter to poison a real order's id. fast-fill solves this with **CREATE2-deterministic addresses**: each adapter's counterpart on every chain is literally *the same address*, `address(this)`.

For CCTP's direct path (`mintFee == 0`), the source sets `mintRecipient = destinationCaller = address(this)`, so only this adapter can call `receiveMessage`. After it mints and consumes the CCTP nonce, it additionally requires that the burn's `messageSender == address(this)`:

```mermaid
flowchart TB
    M["relayer calls settle(message, attestation)"] --> RM["MessageTransmitterV2.receiveMessage"]
    RM -->|"bad attestation / used nonce / caller != destinationCaller"| REV1["revert (rolls back)"]
    RM -->|"valid"| MINT["mint (amount - feeExecuted) USDC to this adapter,<br/>consume nonce"]
    MINT --> P["parse message via BurnMessageV2Lib"]
    P --> C1{"mintRecipient == this?"}
    C1 -->|no| R2["revert MintRecipientMismatch"]
    C1 -->|yes| C2{"config domain == srcDomain?"}
    C2 -->|no| R3["revert UntrustedSourceDomain"]
    C2 -->|yes| C3{"messageSender == address(this)?"}
    C3 -->|no| R4["revert UntrustedSender (anti-forgery)"]
    C3 -->|yes| OK["_settle: reimburse filler or pay recipient"]
```

Anyone can craft their own CCTP burn to our adapter with a fabricated order in `hookData` — but they can't make the burn's `messageSender` *be* our adapter address, so such a burn can never settle here. That's the check that stops an attacker from pre-settling a real order's id and stranding the genuine transfer.

The **OFT** path enforces the analogous property with three gates on `lzCompose`: the caller must be the LayerZero endpoint, the local `from` OFT must be the one in the registry, and the embedded `composeFrom` must equal `address(this)`.

Settlement itself is deliberately boring and safe:

```solidity
owed    = min(arrived, order.outputAmount);
surplus = arrived - owed;
if (filled) { payout(filler, owed); payout(recipient, surplus); }
else        { payout(recipient, arrived); }
status = Settled;
```

`_payout` is a return-value-checked transfer. If a push fails — say the recipient is USDC-blacklisted or reverts — it credits a `claimable[account][token]` ledger instead of reverting, so a hostile recipient can never brick settlement. Effects (status) are written before any external transfer, and every state-changing entrypoint is `nonReentrant`.

---

## The economics

fast-fill's pricing is intentionally simple on-chain and factual off-chain. The **contract** enforces a small signed fee curve; the **demo and relayers** choose sane default values from live market data (gas benchmarks, destination gas price, ETH/USD, Circle's own fee API).

### The premium curve

The fee owed to a filler has two additive parts: an optional flat `baseFee` (a fixed price for the service, owed on any fill) and a **time premium** that is largest right after the order's `startTime` — when the relayer must front capital the longest — and decays linearly to zero at `expectedDeliveryTime`. A late or never-filled order costs the user nothing beyond the bridge.

```
timeSaved = max(0, expectedDeliveryTime − max(fillTime, startTime))
rate      = min(discountRate · timeSaved, maxFeeRate)          [WAD]
timeFee   = outputAmount · rate / 1e18
fee       = min(baseFee + timeFee, outputAmount)
payout    = outputAmount − fee        (paid to the recipient at fill)
```

![The optimistic-fill premium decays to zero at the bridge's delivery time](/images/announcing-fast-fill/pricing-curve.png)

The chart shows all three regimes on an illustrative $1,000 transfer with a 60-second delivery window:

- **The cap plateau (left).** `maxFeeRate` is a per-adapter governance ceiling on the *rate* (deployed at **0.5%**). A user can request an aggressive premium, but the adapter clamps it. In the live Base→Arbitrum run below, the user's premium saturated exactly this 0.5% cap.
- **The linear decay (middle).** As the bridge's expected delivery time approaches, the relayer would be fronting capital for less and less time — so the premium it can earn shrinks proportionally.
- **The flat floor (right).** After the delivery window, only the flat `baseFee` remains (here $0.05, a stand-in for the fill's gas). Beyond that, the premium is zero — filling late earns nothing but the base fee.

Both `baseFee` and `discountRate` are **per-order, user-chosen**. Set `baseFee = 0` for a pure time curve, or `discountRate = 0` for a flat fee. Timing is derived **on-chain**: `startTime = block.timestamp`, and the user signs a *relative* `deliveryWindow`, so `expectedDeliveryTime = block.timestamp + deliveryWindow`. Signing a relative window (rather than an absolute timestamp) means the window a user agreed to holds no matter when a sponsoring relayer actually submits.

### Where a fast-fill fee actually comes from

It's fair to ask: *what does going fast actually cost me?* The demo derives every signed value from factual inputs, so we can decompose a real quote. For a $1,000 fast CCTP transfer to Arbitrum with Circle's Relay Mint enabled:

![Anatomy of a fast-fill fee — the relayer's own cut is sub-cent](/images/announcing-fast-fill/fee-composition.png)

The headline: **everything fast-fill itself adds is a few cents.** The largest line item, the Circle protocol fee, is the *bridge's* — you'd pay it going direct too. The mint-relay fee (which pays whoever submits the destination mint), the fill's gas floor, and the actual speed premium together come to about three cents on $1,000. The time premium in particular is tiny by design: it prices the relayer's capital at a **10% APR opportunity cost** over the seconds it fronts the money, and 10% APR for a few seconds rounds to almost nothing. Users see all of these signed values before they submit, and relayers independently recompute and reject stale or underpriced quotes.

### The overhead of a thin wrapper

Because fast-fill rides the bridge's own message rather than adding a second one, its gas overhead is modest. Measured against a **byte-identical in-EVM mock bridge** (so the bridge's own cost cancels in the subtraction), here is what fast-fill itself adds per operation:

![What the thin wrapper costs: fast-fill's gas overhead per operation](/images/announcing-fast-fill/gas-overhead.png)

For context, a *real* CCTP burn through the adapter costs **≈167,638 gas end-to-end** on an Ethereum-mainnet fork, of which the bridge is the large majority. fast-fill never adds an escrow write or a second cross-chain message — it threads its order through the payload the bridge was already carrying. (On the L2s where it's deployed, the dollar cost of all of this is a fraction of a cent.)

### Speed: who actually waits

This is the part that matters to a user. When a relayer fills, **the user has usable funds in about 1.5 seconds** — regardless of how slow the underlying bridge is. The relayer, not the user, absorbs the bridge's settlement latency, and is paid the premium precisely for taking on that wait and that capital risk.

![When a relayer fills, the user waits ~1.5s — not for the bridge](/images/announcing-fast-fill/latency.png)

*(Bridge settlement times are approximate and route/finality-dependent; the point is the order-of-magnitude gap.)*

### The relayer's business

A fast-fill relayer earns from **two independent roles**, and neither requires a liquidity pool:

1. **Optimistic filling.** When it holds destination inventory and a fill clears its gas-backed profitability floor, it calls `fill(order)`, pays the recipient instantly, and is reimbursed `outputAmount` at settlement — pocketing the premium. Its capital is tied up only for the bridge-latency window (seconds to minutes), which is exactly what the time premium prices.
2. **CCTP mint relaying.** For orders that opt into Circle's Relay Mint (`mintFee > 0`), the relayer polls Circle's attestation and calls `CctpExecutor.execute(...)`, which mints the USDC, pays it the `mintFee`, and forwards the rest to the adapter. This needs only gas — no inventory — and can be done even for orders it didn't fill.

Crucially, there's **no relayer liquidity pool and no protocol escrow**. The in-flight bridged funds are the reimbursement. That makes the capital model dramatically simpler than a solver network: a relayer needs enough working inventory to cover the fills in flight during a bridge-latency window, and nothing more.

---

## `CctpExecutor`: a standalone public good

CCTP has a rough edge: after a burn, *someone* has to submit the destination mint, and Circle's own forwarding service is a paid, centralized convenience. fast-fill ships a generic, permissionless replacement — `CctpExecutor` — that knows about CCTP messages and USDC but nothing about fast-fill orders. Any CCTP integrator can use it.

A source burn sets `mintRecipient = destinationCaller = CctpExecutor` and puts an envelope in `hookData`:

```solidity
struct ExecHook {
    uint256 mintFee;  // USDC paid to whoever calls execute()
    bytes32 target;   // forward recipient OR hook receiver contract
    uint64  gasLimit; // 0 => forward-only, >0 => call target.onCctpExecute(...)
    bytes32 refundTo; // claimant if hook execution fails
    bytes   payload;  // integrator-defined data
}
```

On the destination, **anyone** calls `execute(message, attestation)`: the executor mints the USDC to itself, pays `mintFee` to the caller, and either forwards the remainder to `target` (forward-only mode) or calls `target.onCctpExecute(...)` in the same atomic frame (hook mode). For a fast-fill order, the hook is what settles it.

The accounting for a routed fast-fill order is unchanged — `mintFee` cancels out because it's reserved on the source side:

```
forward − outputAmount
  = (inputAmount − feeExecuted − mintFee) − (inputAmount − maxFee − mintFee)
  = maxFee − feeExecuted ≥ 0
```

so the filler is still reimbursed exactly `outputAmount`, and the recipient still gets the `maxFee − feeExecuted` surplus.

**Batching and directed fees.** CCTP v2 has no on-chain batch mint, so a relayer amortizes the per-transaction base cost by batching the *calls*: `executeBatch(messages[], attestations[], feeRecipient)` relays many messages in one transaction with **partial success** — each item runs in its own `try`/`catch` under a single reentrancy guard, so an item that reverts (already relayed, stale attestation) is skipped and its CCTP nonce stays redeemable, rather than aborting the batch. `FastFillBase` has the symmetric `fillBatch`. Both also support directed payout (`executeTo` / `fillTo`) so a hot wallet can relay while a treasury collects — but these only ever move the relayer's *own* fee/reimbursement; the user-signed recipient and the source-attested delivery target stay authoritative.

---

## Destination executions: act on funds the instant they arrive

An order can carry `hookData` and a user-signed `callbackGasLimit` (capped at **5,000,000 gas**). When the funds are delivered — whether by an optimistic fill or by the bridge settling — a recipient *contract* receives an `onFastFill(orderId, token, amount, hookData)` callback in the **same atomic frame** as the transfer. This is how you bridge-and-do-something in one shot: deposit into Aave, swap on Uniswap, fund a smart account.

The failure policy is governed by the receiver's own revert data, and it's designed so funds are **never stranded**:

```
onFastFill succeeds            → funds delivered, execution ran
reverts RedirectFunds(dest)    → funds delivered to dest instead
reverts anything else / OOG    → funds credited to claimable[recipient] (recover via claim())
```

This mirrors CCTP v2's atomic-hook semantics but is **strictly safer**: because the transfer and callback share one revertable frame, a deterministically-failing hook can never strand the bridged funds. The demo ships two validated hooks — a **Uniswap V3 swap** and an **Aave V3 deposit** — both deployed on Base, Optimism, and Arbitrum, each leaning on the revert-to-redirect rule so a failed action degrades to a plain transfer of the original token to the user.

The hardening here is meticulous. The callback is gas-capped and **return-bomb-safe**. The forwarded gas budget is *guaranteed* by an exact in-frame check that accounts for both nested EIP-150 63/64 deductions — so a relayer that under-funds the transaction reverts the whole fill (forcing a retry) rather than quietly starving the callback. And it all runs behind the existing `nonReentrant` guard with effects written first, so a hostile receiver can't re-enter or claw back funds it wasn't owed.

---

## Gasless and sponsored transfers

Neither users nor relayers should have to hold gas on every chain just to sign. Both adapters support signature-based funding:

- **EIP-2612 single-tx** — batch a `selfPermit` before the action via `multicall([selfPermit(token, …), initiateCCTP(…)])`, so approval and bridge land in one transaction. Works for USDC and USD₮0.
- **Permit2 sponsored intent** (`initiate*For` / `fillFor`) — a user *signs* an off-chain order intent; a relayer submits it and pays the gas, while funds are pulled from the **signer** via Permit2. The signature commits to a **witness** binding the recipient, amounts, timing, pricing, the destination execution, **and** the bridge mode (CCTP fast-vs-finalized + executor routing, or OFT executor options). So a submitting relayer can't re-price, re-time, re-route, or change the destination action of a signed intent. This is proven against the *real* Permit2 in a fork test, including rejected attempts to tamper with the recipient and to flip the transfer speed.

---

## Configuration: one immutable registry, deterministic addresses everywhere

All chain-specific data — CCTP/LayerZero addresses, domains, endpoint ids, per-chain USDC, and each OFT's per-chain `(oft, token)` pair — lives in a single **immutable `FastFillConfig`** contract, deployed once via **CREATE2** so it lands at the *same address on every chain*.

```mermaid
flowchart TB
    subgraph BASE["FastFillBase (abstract)"]
        OB["order book + status machine"]
        FILL["fill() · fillFor()"]
        SET["_settle()"]
    end
    subgraph CB["CallbackExecutor (abstract)"]
        PAY["_payout + claim ledger"]
        HOOK["atomic transfer + callback"]
    end
    CA["CctpAdapter<br/>initiateCCTP() · settle() · onCctpExecute()"]
    CE["CctpExecutor<br/>execute() · forward / hook mode"]
    OA["OftAdapter<br/>initiateOFT() · lzCompose()"]
    CA -- inherits --> BASE
    OA -- inherits --> BASE
    BASE -- inherits --> CB
    CE -- inherits --> CB
    CFG["FastFillConfig<br/>immutable CREATE2 registry"]
    CA --> CFG
    CE --> CFG
    OA --> CFG
```

The payoff is that there is **no per-counterpart wiring to get wrong**. Because the registry, the executor address, the owner, and the fee cap are identical across chains, every adapter is itself CREATE2-deterministic — so the counterpart adapter on the far chain is simply `address(this)`, which is exactly the property the settlement-authentication checks rely on. There are **no owner setters** for addresses, domains, or counterparts; those are read from the registry at call time. And on every use, the adapter **cross-checks its local domain / endpoint id / token against the live bridge contracts** and reverts on any mismatch — a wrong constant can't silently ship. The owner-gated surface is tiny: `setMaxFeeRate` and `setPaused`.

### Many tokens, one code path

`OftAdapter` is generic — parameterized by an `oftId` — and `OftAdapterFactory` stamps out one instance per token at a deterministic, cross-chain-stable address. Onboarding a new OFT (USDe, sUSDe, ENA, USDtb, …) is **purely additive**: add the per-chain rows to the registry, assign an id, and call `deploy(oftId)`. No new adapter code. Because each token gets its own deployment, **every token's reimbursement pool is physically isolated** — a decode or auth bug in one adapter can never reach another's funds.

One honest caveat: a *deployed* adapter is just an address on our side — it doesn't guarantee the token issuer's live OFT has enabled peers for a given route. The USD₮0, USDe, sUSDe, and ENA adapters are deployed on all three chains; USDtb is defined in the registry but not yet stamped out by the factory; and some Ethena routes (e.g. USDe Arbitrum ⇄ Base) currently revert `NoPeer` because the issuer hasn't wired those peers yet. The adapter framework is ready; peer availability is the token issuer's to enable.

---

## Proven on mainnet

fast-fill isn't a testnet demo. The CCTP path has been run **end-to-end on Ethereum-mainnet L2s with real USDC** and Circle's real attestation service.

### The headline run: $1, Base → Arbitrum, filled before settlement

A $1 transfer to a fresh recipient, with a user-chosen premium that capped at the adapter's 0.5%. The relayer fronted the funds on Arbitrum **before** the bridge settled, then was reimbursed when it did.

![Live on mainnet: a $1 Base→Arbitrum transfer, filled before the bridge settled](/images/announcing-fast-fill/waterfall.png)

Reading the waterfall (all figures are the real on-chain record, in USDC):

| Party | Result |
|---|---|
| **Recipient** | **$0.994871 total** — of which **$0.994801 arrived at fill time**, in ≈1.5 seconds, *before* CCTP settled |
| **Relayer** | net **+$0.004999** — the 0.5% premium earned for fronting capital across the bridge-latency window |
| **Bridge** | $0.000200 reserved as `maxFee`; the unspent surplus ($0.000070) flowed to the recipient at settlement |

And the fallback was demonstrated too: two baseline runs with **no relayer** simply delivered the funds when CCTP settled — the recipient received `999,870` units on a $1 transfer (the 130-unit haircut is Circle's fast-transfer fee), at no premium. That's the worst case, and it's exactly the bridge.

### The executor path, live

The newer `CctpExecutor`-routed path has since been deployed on Base, Optimism, and Arbitrum and smoke-tested with live USDC for both **unfilled** and **optimistically filled** orders. One routed Optimism→Arbitrum fill, for example, paid the recipient at fill time, then at settlement had the executor pay the mint relayer its `mintFee`, reimburse the filler, and route the surplus to the recipient — all in the accounting described above, on-chain, with real money.

### The OFT path, de-risked on forks

The LayerZero path targets USD₮0 and the Ethena OFT suite (USDe, sUSDe, ENA). It's proven against the **real USD₮0 OFT and LayerZero endpoint on an Optimism fork** — driving the real mint and the real compose to settle an order — plus live fact-checks of every OFT's on-chain configuration across four chains. A live USD₮0 *source* transfer has been broadcast Optimism→Arbitrum (pending the pathway's source confirmations at the time of writing, not yet confirmed delivered); a full public OFT demo is the next milestone.

### Deployed addresses

All contracts are CREATE2-deterministic — the **same address on Base, Optimism, and Arbitrum** — from a single deployer, with `maxFeeRate = 0.5%`:

| Contract | Address |
|---|---|
| `FastFillConfig` | `0xaec766479DB174110958Bc45D141A2C5eF693DF5` |
| `CctpExecutor` | `0xAFc7bBc0B5fD7A4d9b936349cfE991e5bC6E2a80` |
| `CctpAdapter` (executor-enabled) | `0x9FA37faBfA1Fd31Afe5A5F93e1c4Cd986b27bA75` |
| `OftAdapterFactory` | `0x84Bb5d3142024da8d61CBEE0A4c722a1650fbFcb` |
| `OftAdapter` (USD₮0 / USDe / sUSDe / ENA) | one deterministic address per token |

The demo hooks (`UniswapSwapHook`, `AaveDepositHook`) are deployed and source-verified on all three chains as well.

---

## The security model, at a glance

fast-fill's threat model is small because its trust surface is small. A condensed version of the full table:

| Vector | Defense |
|---|---|
| Double-fill / fill-after-settle | `fill` requires `status == None`. |
| Replay of a bridge message | The bridge consumes its own nonce; plus a `status != Settled` app guard. |
| Fake-order fill | Non-matching `orderId` ⇒ filler is never reimbursed (self-punishing). |
| Forged CCTP burn to our adapter | `messageSender == address(this)` rejects burns not initiated by our same-address adapter. |
| Routed CCTP nonce griefing | `destinationCaller = CctpExecutor`; only the executor can consume the message. |
| Caller redirecting bridged funds | `executeTo`/`fillTo` redirect only the relayer's *own* fee; recipient & delivery target stay authoritative. |
| Forged OFT compose | Three gates: endpoint caller, local OFT, `composeFrom == address(this)`. |
| Misconfigured registry | Local domain/eid/token cross-checked live against the bridge contracts at construction; a mismatch reverts the deploy. |
| Sponsor altering a signed intent | Permit2 witness binds the intent *and* the bridge mode; tampering recovers a different signer and reverts. |
| Hostile destination receiver | `onFastFill` is gas-capped, return-bomb-safe, `nonReentrant`; any failure routes to redirect/claimable. |
| Recipient/filler revert (e.g. blacklist) | `_payout` falls back to a `claimable` ledger; settlement still completes. |

The contracts ship with **141 tests** — pure-library fuzzing of the pricing curve, full CCTP and OFT lifecycles, the executor's routed/forward/hook modes, factory pool-isolation, adversarial races, 16k+-call invariants, gasless flows, destination-execution edge cases (reentrancy, return-bomb, gas-budget, atomic claw-back), gas benchmarks, and mainnet-fork checks against the real CCTP, USD₮0, Uniswap, Aave, and Permit2 contracts.

---

## Status & what's next

**This is a prototype. It is not audited.** It's deployed for demonstration with tight caps on transfer size, and the backend relayer holds a hot key — so the live demo runs on tiny amounts. With that said, the design is intentionally close to production-shaped, and the iteration points are known:

- **Circle Gateway relayer funding** — a designed-but-unbuilt path that lets a relayer keep a single *unified* USDC balance and mint destination inventory just-in-time before filling, eliminating pre-positioned inventory entirely. The design is front-run-safe by construction (the mint is bound to the relayer, and the fill pulls from `msg.sender`, so a copycat's transaction reverts and rolls back the mint).
- **Surplus routing** — currently always to the recipient; an intended point of flexibility.
- **More tokens and chains** — additive for OFTs (assign an id, add rows, deploy); a new chain means publishing a new registry version.
- **A live OFT demo** and, ultimately, an audit.

The philosophy won't change, though. fast-fill is a **thin, honest layer**: it makes a cross-chain transfer faster when someone's willing to help, it makes that help trustless and permissionless, and when no one helps it gets out of the way and lets the bridge do exactly what it always would. Speed when you can get it; safety, always.

---

## Try it and dig in

- **Interactive demo** — connect a wallet on Arbitrum / Optimism / Base, send a real (capped) transfer, and watch a relayer fill it in seconds.
- **`docs/ARCHITECTURE.md`** — the full design deep-dive, with every authentication flow and the complete security table.
- **`docs/PRICING.md`** & **`docs/GAS.md`** — the off-chain quote model and the gas methodology behind the charts above.
- **`DEMO.md`** — the complete mainnet transaction record for the run charted here.
- **`relayer/`** — the autonomous Rust relayer bot, if you want to run one yourself.

*fast-fill — instant when it can be, never worse than the bridge.*
