Trading

Trading outcome tokens

Outcome tokens (CTF positions) are traded on AMMs. Pools are always outcome token / main collateral for the chain.

Swapr (Algebra V3) and Uniswap V3 use the same swap interface, so you can use the same router ABI for both: exactInputSingle and exactOutputSingle.

Note: The code in this guide is provided as an example (direct router calls with viem). You can also use the official Uniswap or Swapr SDK in your project and call them directly to build and send swaps; the logic for routes, amounts, and slippage is the same.


Main collateral by chain

Pools are quoted against the main collateral. Use these token addresses when building swap paths:

Chain
Main collateral
Address

Gnosis (100)

sDAI

0xaf204776c7245bf4147c2612bf6e5972ee483701

Ethereum (1)

DAI

0x6B175474E89094C44Da98b954EedeAC495271d0F

Base (8453)

sUSDS

0x5875eee11cf8398102fdad704c9e96607675467a

Optimism (10)

sUSDS

0xb5b2dc7fd34c249f4be7fb1fcea07950784229e0

See also COLLATERAL_TOKENS / TOKENS_BY_CHAIN in the app’s config.


Router addresses

Chain
DEX
Swap router address

Gnosis

Swapr

0xffb643e73f280b97809a8b41f7232ab401a04ee1

Ethereum

Uniswap V3

0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45

Base

Uniswap V3

0x2626664c2603336E57B271c5C0b26F421741e481

Optimism

Uniswap V3

0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45

Use the same router ABI (Uniswap V3–compatible) for Swapr and Uniswap V3.


Router ABI (shared)

Use the Uniswap V3 SwapRouter ABI. Relevant functions:

  • exactInputSingle(ExactInputSingleParams) – swap an exact amount of token-in for a minimum amount of token-out (e.g. spend X collateral, get at least Y outcome tokens).

  • exactOutputSingle(ExactOutputSingleParams) – swap to receive an exact amount of token-out, with a maximum amount of token-in (e.g. get exactly Y outcome tokens, spend at most X collateral).

Params (same for both DEXs):

You need the fee tier of the pool (e.g. from the factory or subgraph). Common values: 500 (0.05%), 3000 (0.3%), 10000 (1%). Use sqrtPriceLimitX96 = 0 for no price limit.


Quoters (get a quote before trading)

To show the user how much they will receive or spend, call a Quoter contract before sending the swap. Quoters expose quoteExactInputSingle (exact amount in β†’ minimum out) and quoteExactOutputSingle (exact amount out β†’ maximum in). They are intended to be used off-chain via eth_call: the contract reverts with the result instead of returning it, so you must call and then decode the revert data.

Quoter addresses

Chain
DEX
Quoter address

Gnosis (100)

Swapr

0xcBaD9FDf0D2814659Eb26f600EFDeAF005Eda0F7

Ethereum (1)

Uniswap V3

0x61fFE014bA17989E743c5F6cB21bF9697530B21e (QuoterV2)

Base (8453)

Uniswap V3

0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a (QuoterV2)

Optimism (10)

Uniswap V3

0x61fFE014bA17989E743c5F6cB21bF9697530B21e (QuoterV2)

Swapr (Gnosis) uses a different interface: no fee argument; the functions return (amount, fee) so you get the pool fee from the quote. Uniswap V3 takes fee as a parameter and returns only the amount.

Swapr Quoter (Gnosis) β€” Algebra V3

On Gnosis, the Swapr Quoter at 0xcBaD9FDf0D2814659Eb26f600EFDeAF005Eda0F7 uses:

  • There is no fee parameter; the pool fee is discovered by the quoter and returned as fee.

  • Use limitSqrtPrice = 0 for no price limit.

  • Use the returned fee when calling the SwapRouter for the actual swap.

Uniswap V3 QuoterV2 ABI (single-pool)

Uniswap QuoterV2 (used on Ethereum, Base, Optimism) takes a single struct per function and returns four values; the first is the amount. Use sqrtPriceLimitX96 = 0 for no limit.

The first return value is amountOut (or amountIn for quoteExactOutputSingle); the other three are sqrtPriceX96After, initializedTicksCrossed, and gasEstimate.

Getting the quote (viem)

Quoter functions are not view: they simulate the swap and revert with the result. So you must simulate the call and decode the revert data to get the amount (do not rely on result.data from a successful eth_call, because the contract reverts by design and some RPCs return a failed call).

Quote exact input (e.g. β€œI spend 10 collateral β†’ how many outcome tokens?”):

Swapr quote (Gnosis): same idea, but use the Swapr Quoter ABI (no fee in args; returns [amountOut, fee] or [amountIn, fee]). Use the returned fee when building the swap router call:

Use the same simulate-and-decode-revert pattern as for Uniswap QuoterV2 so behaviour is consistent across RPCs.


Shared: ROUTERS and COLLATERAL

Define these once; the examples below use them as if already in scope.


Example: buy outcome tokens (collateral β†’ outcome)

User spends collateral to receive outcome tokens. Use exactInputSingle: tokenIn = collateral, tokenOut = outcomeToken.


Example: sell outcome tokens (outcome β†’ collateral)

User sells outcome tokens for collateral. Use exactInputSingle: tokenIn = outcomeToken, tokenOut = collateral.


Example: buy exact amount of outcome (exactOutputSingle)

When you want to receive exactly N outcome tokens and spend at most X collateral, use exactOutputSingle:


Token order and pool fee

  • Token order in the pool is defined by the contract (token0 < token1 by address). Your swap’s tokenIn / tokenOut are the token addresses; the router uses the correct pool.

  • Fee tier must match the existing pool (e.g. 3000 for 0.3%). You can read it from the pool contract or from the DEX subgraph (e.g. Swapr on Gnosis, Uniswap on other chains).

For reference, the app derives the liquidity pair (outcome token vs collateral) in getLiquidityPair and uses the same router ABI for both Swapr and Uniswap.

Last updated