BopAMM is currently undergoing contract audits. Before audits are complete, integrators are advised to implement their own safety checks on top of swaps against BopAMM.
swapWithFallback() is BopAMM’s safety net for high-value flow that can’t tolerate a same-block-execution failure (StaleBook, StaleUpdate) or insufficient on-chain liquidity. The function tries the BopAMM leg in a try/catch and falls through on any revert to a whitelisted fallback target with pre-encoded calldata. The standard fallback target is the Bebop RFQ settlement contract.
You don’t compose this calldata yourself. The BopAMM /quote endpoint builds the whole thing: it prices 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 swap(), but you trade reliably even when the registry is behind or the on-chain 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.
swap() 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 swapWithFallback(...) call.
Behind the endpoint, the RFQ leg is quoted with the BopAmmV2 contract as the
taker_address, because that contract is the on-chain taker that pulls tokenIn and delivers tokenOut on the fallback path. In self-execution mode the maker’s signature in the RFQ calldata is sufficient and no taker signature is required, which is why requiredSignatures is empty.Submit it
Approve the BopAmmV2 contract fortokenIn if you haven’t already (see Approve the BopAMM contract), then build, sign, and submit tx. Unlike a plain swap(), you don’t have to route this through a builder: the fallback is caught inside the same transaction, so a public-mempool submission still settles, via RFQ, when a supporting builder doesn’t win the block. The BopAMM leg settles only when a supporting builder includes the transaction and the on-chain book can fill. The simulation and gas-estimation are identical to a plain swap; the example below submits through a builder RPC.
What the calldata encodes
You don’t assemble this yourself, but it helps to know whattx.data decodes to. The on-chain function is:
swap() and apply to the BopAMM leg. The last two carry the fallback the endpoint composed for you.
Caveats
A few BopAMM-specific behaviors to be aware of:recipientis BopAMM-only. The fallback leg delivers to the receiver baked intofallbackCallData. The endpoint quotes the RFQ leg with yourreceiver_addressand rejects any mismatch, so both legs deliver to the same destination - but it’s yourreceiver_addressthat drives it.minAmountOutis BopAMM-only. It does not protect the fallback leg; the fallback’s slippage is whatever the RFQ quote committed to.- One shared
expiry. The endpoint sets the BopAMM leg’sexpiryto the RFQ quote’s expiry (typically ~60-75s) and reports it as the responseexpiry. Your whole transaction must land before then, including any builder delay. - No native ETH out on the fallback path.
swapWithFallbackreverts withEthOutNotSupportedInFallbackiftokenOutis the native ETH sentinel. ETH out works on plainswap()and on the BopAMM leg, just not as the fallback target’s output. - Residual sweep. If the fallback leg consumes less than
amountIn, any residualtokenInor ETH is swept back tomsg.senderautomatically.
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.
Whitelisting
The endpoint composes the fallback against the Bebop RFQ settlement contract, which is whitelisted by default. The contract owner controls the whitelist viasetFallback(). If you need a different fallback target (for example an internal router of your own), reach out via support - this isn’t a self-serve operation.