# Only USDC crosses, and it takes fifteen minutes

> Most plans span more than one chain without mentioning it. Two constraints shape every one, and both surprise people.

- Source: https://defiloops.com/blog/only-usdc-crosses-and-it-takes-fifteen-minutes
- Published: 2026-06-23
- Category: Architecture
- Tags: bridging, multi-chain, cctp, execution
- Author: DeFiLoops

---
"My wallet holds $1,000 USDC on Base, $1,000 on Ethereum and $1,000 on Arbitrum. Lend each
one to a lending pool."

"Take $100 USDC on Base and buy XAUT from Ethereum."

Both are real requests. Neither mentions a bridge. The first does not need one; the second
cannot avoid one. Telling those apart is most of what happens between your sentence and a
transaction, and two constraints decide the shape of the answer.

## Constraint one: only USDC crosses

The crossing in the catalogue is Circle's CCTP, and CCTP carries USDC. Not WETH, not cbBTC,
not tokenized gold.

That single fact rewrites plans. Take the gold request: you have dollars on Base, you want
an asset that lives on Ethereum. There are two shapes available in principle —

<Compare left="Buy here, bridge the asset" right="Bridge the dollars, buy there" verdict>
  <Fragment slot="left">
    Swap USDC to XAUT on Base, then move the XAUT to Ethereum.

    Cannot be expressed. There is no crossing for XAUT, so this plan is refused when it is
    written.
  </Fragment>
  <Fragment slot="right">
    Move the USDC to Ethereum, then swap there.

    The only shape that exists, so it is the one you get — whether or not you thought about
    it.
  </Fragment>
</Compare>

<Callout type="danger" title="A bridge sized from a swap that produced WETH is refused">
  This is the version that surprises people who are being careful. If an earlier step
  produces WETH and you size the crossing from it, validation refuses — correctly, because
  the crossing cannot carry WETH. The sentence said nothing about USDC, so the refusal
  feels like it came from nowhere.
</Callout>

## Constraint two: fifteen minutes, and it cannot be hurried

A crossing is not a transaction that takes a while. Value leaves one chain, time passes,
and value arrives on another. About fifteen minutes, set by Circle, not by us.

Everything downstream follows from that.

<Spec title="What the wait does to a plan" rows={[
  ['Steps on the far side cannot start early', 'The plan is built around the gap rather than hoping'],
  ['A runtime amount cannot cross it', 'A step after a bridge cannot spend “whatever the swap returned” — the two are in different transactions on different chains'],
  ['The run has to survive it', 'Fifteen minutes is long enough for us to ship an update mid-run, so progress lives in a database, not in a process’s memory'],
  ['Bridges go last where possible', 'Everything that can be done on one side is done before the wait, not after'],
]} />

<Callout type="warn" title="The bus cannot cross a transaction">
  Inside one transaction a step can spend exactly what the previous step produced. Across a
  crossing it cannot — there is no shared moment for the number to live in. A plan that
  tries reports `NothingDelivered`, which is the correct refusal and a confusing error until
  you know why.
</Callout>

## What the ordering actually does

Given those two constraints, a multi-chain plan is not "the steps you listed, in the order
you listed them".

Take the three-wallet request at the top. Nothing about lending on Base depends on lending
on Arbitrum, so those do not queue — they run at the same time. No crossing is needed at
all, because the money is already where it needs to be. The right plan for that sentence has
no bridge in it, and a system that assumed "multi-chain means bridging" would have added
three unnecessary crossings and charged you for them.

Now take a plan that does need to cross:

<Steps>
  <Step title="Fold what can be folded">
    Steps that can share a transaction are merged. “Approve, then supply” as one transaction
    means the approval cannot outlive a supply that failed.
  </Step>
  <Step title="Cluster by chain">
    Everything doable on Base is grouped, so the plan crosses as few times as it can.
  </Step>
  <Step title="Put the crossings late">
    A crossing is the slowest and most expensive step. Anything that can happen before the
    wait, does.
  </Step>
  <Step title="Break where value cannot be carried">
    Where a runtime amount cannot survive to the next step, a new transaction starts. The
    board shows that as a dotted line before you approve it.
  </Step>
</Steps>

## What it costs

Flat, which matters more than the percentage.

<StatRow>
  <Stat value="$0.50" label="per crossing" note="Flat, regardless of size." />
  <Stat value="0.1%" label="crossing fee" note="Of the amount sent." />
  <Stat value="~15 min" label="per crossing" accent note="Set by Circle. Cannot be hurried." />
</StatRow>

Because the fee is flat, it dominates a small plan and disappears in a large one. Three
crossings on a $1,000 plan is $1.50 of bridge fee — about 0.15%, which is a month of yield
on a lending position. The same three crossings on $100,000 are 0.0015%, and by then
slippage on the swaps matters far more than the bridges do.

<Callout type="note" title="You never bridge gas">
  A separate key of ours pays network fees on every chain and is reimbursed from the plan in
  an asset the plan already holds. You do not have to hold the native coin of a chain you
  have never used, which is the part of multi-chain work that is usually most annoying.
</Callout>

## Ask before you plan

Because the constraints are specific, "can I do this?" is usually really "can I do this
**on that chain**?" — and those have different answers often enough to matter.

Asking which assets, chains and operations exist costs nothing and takes one question. It
is a much better use of thirty seconds than discovering the answer from a validation error
after you have written the plan.