Skip to main content
This guide walks you through a complete BopAMM swap on Ethereum: approving the router, fetching the current state, quoting against the live on-chain book, simulating the router swap to catch reverts, and submitting it through a supported block builder. You’ll sell 1 USDC for WETH.
What you’ll build: A USDC to WETH swapWithAllowance transaction against BopAMM, quoted and simulated mid-block, then submitted through a block builder.Time required: 15-20 minutesPrerequisites: Basic EVM knowledge and web3.py, a BopAMM API key, a funded signing key, and the ability to submit transactions through a supported builder RPC.

Setup

Install web3, eth-account, and httpx, then define the constants and contract handles used throughout. This quickstart uses BopAmm.quote() to quote the swap and BopAmmRouter.swapWithAllowance() to execute it.
Keep API_KEY and PRIVATE_KEY out of source. Load them from environment variables (for example with os.environ and python-dotenv) rather than hardcoding them.

1. Approve the BopAMM router

Before swapping ERC-20 input, the router needs permission to pull your USDC. Approve BopAmmRouter for the scope of this demo (10 USDC). This is the standard check-and-approve pattern. See Token Approvals for the canonical helper and the max-vs-exact tradeoffs.
A few BopAMM-specific notes:
  • The approval target is the BopAmmRouter contract (BOPAMM_ROUTER_ADDRESS). The core pool does not pull taker funds on the router path.
  • Native ETH in needs no approval. Send msg.value == amountIn and pass the sentinel address 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE as tokenIn.
  • Cross-pair swaps (for example WETH to WBTC) don’t require a USDC approval. Intermediate USDC stays inside the contracts.
This demo approves a fixed 10 USDC to keep the allowance scoped. Programmatic integrators usually approve the maximum amount once per token to avoid re-approving on every trade. See Token Approvals.

2. Fetch the live state

You can get the current snapshot two ways: a call to GET /state, or the streaming WebSocket, which pushes a fresh snapshot whenever a new aggregated book is available. Both carry the same data: the snapshot block, the aggregated books, and the state_overrides you need to quote against the live book before the on-chain update lands. Use REST for a single swap and the stream for continuous quoting.
The operator exposes the current aggregated book at GET /state.
Example response (abridged):
Key fields:

3. Get a quote

quote() is a view function on the core pool that walks the book and returns the expected output for a given input. To quote against the latest book at any point in the block, apply the state_overrides as a stateDiff against the contract from the snapshot.
For native ETH at the router boundary, quote the core pool with WETH. The router normalizes the native ETH sentinel to WETH before calling BopAmm.

4. Add a fee (optional)

To charge an integrator fee on the BopAMM leg, set FEE_BPS and FEE_RECIPIENT before building the router calldata:
The fee is taken from successful BopAMM output before minAmountOut is checked, so quote and simulate with amount_after_router_fee(...) as shown above. A configured percentage of the fee goes to the protocol; the rest goes to FEE_RECIPIENT.

5. Simulate and size gas

Before broadcasting, run the router swap as an eth_call against the same override to catch reverts without spending gas, then estimate gas with the override to set a real gas limit.
Pass the same state_override to estimate_gas. A plain estimate_gas at the chain head can revert before the current book has landed on-chain.

6. Submit through a block builder

This is the step that differs from RFQ and Aggregation. A plain BopAMM swap settles reliably when a builder that supports BopAMM includes it in the same block as the matching book update. Current supported builders are:
  • Titan
  • BuilderNet
  • Quasar
  • Bombora
For a plain swapWithAllowance, submit directly to a supported builder RPC. A public-mempool submission only goes through when a supporting builder happens to win the block. To drop this constraint, use swapWithFallback, which settles via RFQ in the same transaction when the BopAMM leg can’t land.
Fetch EIP-1559 fees from Blocknative:
Each estimate pairs a confidence (the chance of inclusion in the next block) with the fees that buy it. Higher confidence costs more:
Pick the cheapest estimate that still clears your confidence threshold, then build and sign the transaction. Pad the estimated gas (here by 50%) to absorb book changes between simulation and inclusion:
Then send the raw transaction to the builder RPC:
The builder returns a JSON-RPC result with the transaction hash:
The result is your transaction hash. Track it on a block explorer to confirm it landed in the target block.
Can’t tolerate a same-block miss? The /quote endpoint returns ready swapWithFallback calldata that tries BopAMM first and settles via RFQ if the BopAMM leg can’t land. See Falling back to RFQ.

Next steps

Fees

Add optional integrator fees to router calldata or /quote.

Direct pool integration

Use push-payment swap or callback settlement directly against BopAmm.

Falling back to RFQ

Get ready swapWithFallback calldata from the /quote endpoint.