Skip to main content
BopAmmRouter.swapWithFallback() is BopAMM’s safety net for high-value flow that can’t tolerate a same-block-execution failure or insufficient on-chain liquidity. The function tries the BopAMM leg in a try/catch and falls through on any revert to an allowlisted fallback adapter with pre-encoded calldata. The standard fallback adapter executes against Bebop RFQ settlement. You don’t compose this calldata yourself. The BopAMM /quote endpoint builds the whole thing: it prepares the BopAMM leg, fetches a matching RFQ quote, and returns a ready swapWithFallback(...) call in the response tx. You sign and submit it like any other transaction. There’s no separate RFQ request, no EIP-712 signature, and no calldata splicing on your side. You burn more gas than a plain swapWithAllowance(), but you trade reliably even when the BopAMM leg can’t land or the book is too thin.

When to use it

  • High-value flow where a single revert is more expensive than the gas overhead of carrying a fallback.
  • Long-tail assets with sparse maker coverage on BopAMM where the on-chain book may not always reach minAmountOut.
  • Bursty traffic where you want to avoid coordinating around builder windows for every swap.
If you’re routing small, frequent flow on majors and can submit through a supported builder, plain swapWithAllowance() is cheaper. Use swapWithFallback selectively rather than as the default.

Get the fallback calldata

Request a quote from the BopAMM /quote endpoint. When your partner key has the RFQ fallback feature, the response’s tx.data is a complete BopAmmRouter.swapWithFallback(...) call.
The response is a standard Bebop quote. The fields that matter for the fallback path:

Submit it

Approve the BopAMM router for tokenIn if you haven’t already (see Approve the BopAMM router), then build, sign, and submit tx. Unlike a plain swapWithAllowance(), you don’t have to route this through a builder: the fallback is caught inside the same transaction, so a public-mempool submission can still settle via RFQ when the BopAMM leg can’t land.

What the calldata encodes

You don’t assemble this yourself, but it helps to know what tx.data decodes to. The on-chain function is:
The first six parameters define the BopAMM leg. The last three carry the fallback adapter and router fee configuration.

Fees

To have the endpoint encode a router fee, pass both fee and fee_recipient to /quote. The endpoint packs the fee into the returned swapWithFallback calldata and returns buyTokens[].amount / minimumAmount net of the BopAMM router fee.
The router fee is charged only when the BopAMM leg succeeds. A configured percentage of the fee goes to the protocol, and the rest goes to fee_recipient. Fallback output is not charged by the BopAMM router.

Caveats

A few BopAMM-specific behaviors to be aware of:
  • minAmountOut protects both paths. On the BopAMM path it is checked after router fees. On the fallback path it is checked against fallback output.
  • Fallback output is not router-fee charged. Any RFQ terms or fees are part of the embedded RFQ calldata.
  • One shared deadline. The endpoint sets the BopAMM leg’s deadline to the RFQ quote’s expiry and reports it as the response expiry. Your whole transaction must land before then.
  • Native ETH is router-only. The router maps the native ETH sentinel to WETH internally and unwraps WETH for native output. Pairs that normalize to the same token are invalid.
  • Residual sweep. If the fallback leg consumes less than amountIn, any residual tokenIn or ETH is swept back to msg.sender automatically.

Events

The events emitted depend on which leg actually settled: Off-chain, watch for SwapFallback to detect when your fallback paths are firing. A spike in fallback usage on a specific asset usually means the BopAMM book is too thin for your typical size on that pair - either size down, route elsewhere, or contact the team to broaden maker coverage.