Skip to main content
In a Sauce program, swap with @sauce/router’s function for the venue (uniswapV2, uniswapV3, uniswapV4, curve, balancerV2, …; Slipstream, PancakeSwap V3 and Algebra pools through uniswapV3), with a minimum output and, where the pool takes one, a price limit (the @sauce/router reference; several pools under one limit, the distributed swap).
StableSwap AMM optimized for low-slippage swaps between pegged assets (stablecoins, wrapped tokens). Uses a specialized invariant that provides near-zero slippage for like-kind assets while maintaining AMM properties.

What it offers

  • swap: Exchange tokens within a pool using index-based routing
  • addLiquidity: Add liquidity with flexible token amounts (can be imbalanced)
  • removeLiquidity: Remove liquidity proportionally or single-sided

Notes

  • Pool tokens are indexed (i, j) not addressed; you must know the token order for each pool
  • Common pool token orders: 3pool = [DAI(0), USDC(1), USDT(2)]
  • exchange_underlying is used for metapools or lending pools where tokens wrap underlying assets
  • remove_liquidity_one_coin is useful for single-sided withdrawal (higher slippage than proportional)
  • Each pool is a separate contract; use the AddressProvider or registry to discover pools
  • RouterNG enables cross-pool routing for multi-hop swaps across different pools
  • The get_virtual_price never decreases and represents the LP token value growth over time
  • Tokens must be ERC20-approved to the pool contract (not a router) for direct pool swaps
  • For Router NG swaps, approve tokens to the Router NG contract
  • The StableSwap-NG pool interface (plain and meta pools). Classic pools such as 3pool have their own shape: see CurveThreePoolABI below.
  • 3pool (threePool in the addresses), a classic StableSwap pool. Its liquidity arrays are fixed-size, and its state-changing functions return nothing: read amounts as balance changes.
  • From a Pot program, @sauce/router swaps at the pool directly: curve(pool, tokenIn, tokenOut, amountIn, i, j, uint256Indices, minOut, recipient), with uint256Indices false for StableSwap and NG pools (int128 indices) and true for CryptoSwap, approves the pool for exactly amountIn and calls the 4-argument exchange with minOut as min_dy, without decoding a return (3pool-era pools have none); the allowance ends at zero, and it returns the Pot’s balance change, forwarded when the recipient is not the Pot. tryCurve catches a failed exchange, resets the approval and returns 0. The curveSwap action is the same call. The Sauce Router’s own Curve handler cannot trade a pool whose exchange returns nothing, nor a uint256-index pool

Its names in a program

On Ethereum, Curve is a namespace: its contracts need no import.

Deployments

ABI

CurveAddressProviderABI

import CurveAddressProviderABI from "./protocols/curve/CurveAddressProviderABI.json"; Speaks for: addressProvider.
  • get_registry() view returns (address)
  • get_address(uint256 _id) view returns (address)

CurveRouterNGABI

import CurveRouterNGABI from "./protocols/curve/CurveRouterNGABI.json"; Speaks for: routerNG.
  • exchange(address[11] _route, uint256[5][5] _swap_params, uint256 _amount, uint256 _expected, address[5] _pools) payable returns (uint256)
  • exchange(address[11] _route, uint256[5][5] _swap_params, uint256 _amount, uint256 _min_dy, address[5] _pools, address _receiver) payable returns (uint256)
  • get_dy(address[11] _route, uint256[5][5] _swap_params, uint256 _amount, address[5] _pools) view returns (uint256)

CurveStableSwapABI

import CurveStableSwapABI from "./protocols/curve/CurveStableSwapABI.json";
  • exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) returns (uint256)
  • exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) returns (uint256)
  • add_liquidity(uint256[] amounts, uint256 min_mint_amount) returns (uint256)
  • remove_liquidity(uint256 _amount, uint256[] min_amounts) returns (uint256[])
  • remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount) returns (uint256)
  • get_dy(int128 i, int128 j, uint256 dx) view returns (uint256)
  • get_virtual_price() view returns (uint256)

CurveThreePoolABI

import CurveThreePoolABI from "./protocols/curve/CurveThreePoolABI.json"; Speaks for: threePool.
  • exchange(int128 i, int128 j, uint256 dx, uint256 min_dy)
  • add_liquidity(uint256[3] amounts, uint256 min_mint_amount)
  • remove_liquidity(uint256 _amount, uint256[3] min_amounts)
  • remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount)
  • get_dy(int128 i, int128 j, uint256 dx) view returns (uint256)
  • get_virtual_price() view returns (uint256)

Next steps