On this page

Uniswap V3

Swap USDC and WETH through one adapter per direction. Set the output floor, check the pool and recover the final private note.

Configure a direction and fee tier#

The default Queue pair swaps USDC and WETH through the existing Uniswap V3 0.3% pool. Bootstrap deploys a UniswapV3ActionAdapter for each direction and registers each route separately. These are swaps using external liquidity; there is no new Uniswap pool or LP position.

Each adapter stores its Pool, router, factory, input, output and fee at deployment. Both directions use operation 0 and zero actionData. The fork uses the legacy SwapRouter tuple with router02=false. The contract also supports a Router02 tuple when selected at deployment. Match that flag to the router interface in your configuration.

A private input, a public action and its returned note
A private input, a public action and its returned note

Check the router, factory and pool#

Bootstrap checks code hashes, factory lookup, tokens, fee and nonzero in-range liquidity. The adapter saves the router, factory and pool runtime hashes and checks the route before swapping. Price and liquidity can still change while those contracts keep the same identity.

ContractEthereum address in the fixture
USDC/WETH 0.3% pool0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8
Legacy SwapRouter0xE592427A0AEce92De3Edee1F18E0157C05861564
V3 factory0x1F98431c8aD98523631AE4a59f267346ea31F984
QuoterV20x61fFE014bA17989E743c5F6cB21bF9697530B21e
WETH0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
USDC0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48

Set minOut in the output token's units#

swap-usdc-weth takes six-decimal USDC and returns eighteen-decimal WETH. swap-weth-usdc reverses those units. amountIn is fixed by the proof. Get an executable quote for that input and compute minOut using the output decimals, rather than deriving it from a displayed USD value.

Save the quote block and hash, apply the allowed slippage choice and show the minimum and deadline to the user. The browser worker and relay check the route and output again. If price moves below the floor, execution reverts and the input remains unspent. A zero floor is rejected.

typescript
// Read-only factory identity check; ethers v5.
const factory = new ethers.Contract(
  '0x1F98431c8aD98523631AE4a59f267346ea31F984',
  ['function getPool(address,address,uint24) view returns (address)'],
  provider,
);
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const WETH = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const pool = await factory.getPool(USDC, WETH, 3000, { blockTag: quotedBlock });
// 3000 is 0.3% in millionths. Authenticate code and token0/token1/fee too.
const minOut = expectedOut.mul(10000 - slippageBps).div(10000);
if (minOut.isZero()) throw new Error('Output floor rounds to zero');

Call the router and check the result#

The adapter pulls the input from the Pool and compares both balances. It grants that amount to the configured router, calls exactInputSingle with the Pool as recipient and clears the allowance. The Pool's output increase must agree with the router's return value and meet the proof's minimum.

This route sets no sqrt-price limit and requires actionData to be zero. The output floor and deadline come from the user's proof. execute accepts calls only from the configured Pool, so an EOA call gives OnlyPrivacyPool. Prepare the private action and proof, then submit through the Pool/router flow.

Register both directions and scan the output#

Admit USDC and WETH, then call publisherSetSupportedAction for each adapter with operation 0 and its input/output pair. The Pool stores the adapter code hash. The proof includes the adapter, tokens, amount, minimum, deadline and settlement owner.

Stage 1 reserves the USDC or WETH received. Stage 2 creates the private note, which the scanner recovers from authenticated history. The default router performs both in one transaction. For two-stage submission, show pending output until finalization. Keep change notes and unresolved submissions across refreshes so the app does not reuse the same inputs after losing a response.

Explain the public swap and supported extensions#

The swap reveals its pair, direction, amounts and timing. The note owner is absent from the ordinary private spend's venue calldata, though amounts and timing can still link activity. Explain that before the user proves the action; router submission does not hide the external order.

The default adapters cover USDC/WETH swaps. Arbitrary pairs, stocks, LP provision and V4 hooks need their own integrations. Native ETH uses a separate Pool wrapping path. To add a pair, review both assets and liquidity, deploy direction adapters and publish the routes. For multi-hop swaps or swap-to-vault flows, use an immutable action plan.

Retry a swap or withdraw the input asset#

RouteChanged means the router, factory or pool no longer matches configuration. InsufficientOutput means the Pool received too little or the router reported a different amount. InexactInput and InexactConsumption mean unexpected token movements. Check receipts before preparing a replacement when submission status is uncertain.

WETH can leave through a screened ERC-20 withdrawal without reverse-swap liquidity; USDC has its own withdrawal path. Test those transfers with route revocation, slippage rollback, scan recovery and allowance cleanup. UniswapV3ActionAdapter tests cover their fixtures. Adding a pool needs the same checks with that pool's contracts and liquidity.