> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Curve Finance (curve)

> StableSwap AMM optimized for low-slippage swaps between pegged assets (stablecoins, wrapped tokens).

> **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](https://docs.eco.com/sauce-libraries/router); several pools under one limit, [the distributed swap](https://docs.eco.com/quickstarts/sauce/distributed-swap.md)).

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.

| Fact | Value |
| - | - |
| Category | DEX |
| Family | none |
| Namespace | `Curve` on ethereum, optimism, gnosis, polygon, fantom, base, arbitrum, avalanche |
| Chains | ethereum, optimism, gnosis, polygon, fantom, base, arbitrum, avalanche |

## 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.

```ts theme={null}
function main() {
  // Ethereum's addressProvider, `0x0000000022D53366457F9d5E68Ec105046FC4383`.
  require(Curve.AddressProvider != 0);
}
```

## Deployments

| Chain | Contract | Address | In a program |
| - | - | - | - |
| [Ethereum](https://docs.eco.com/sauce-sdk/reference/chains/ethereum.md) | addressProvider | `0x0000000022D53366457F9d5E68Ec105046FC4383` | `Curve.AddressProvider` |
| [Ethereum](https://docs.eco.com/sauce-sdk/reference/chains/ethereum.md) | crvToken | `0xD533a949740bb3306d119CC777fa900bA034cd52` | `Curve.CrvToken` |
| [Ethereum](https://docs.eco.com/sauce-sdk/reference/chains/ethereum.md) | routerNG | `0x16C6521Dff6baB339122a0FE25a9116693265353` | `Curve.RouterNG` |
| [Ethereum](https://docs.eco.com/sauce-sdk/reference/chains/ethereum.md) | threePool | `0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7` | `Curve.ThreePool` |
| [Optimism](https://docs.eco.com/sauce-sdk/reference/chains/optimism.md) | routerNG | `0x0DCDED3545D565bA3B19E683431381007245d983` | `Curve.RouterNG` |
| [Gnosis](https://docs.eco.com/sauce-sdk/reference/chains/gnosis.md) | addressProvider | `0x0000000022D53366457F9d5E68Ec105046FC4383` | `Curve.AddressProvider` |
| [Polygon](https://docs.eco.com/sauce-sdk/reference/chains/polygon.md) | addressProvider | `0x0000000022D53366457F9d5E68Ec105046FC4383` | `Curve.AddressProvider` |
| [Fantom](https://docs.eco.com/sauce-sdk/reference/chains/fantom.md) | addressProvider | `0x0000000022D53366457F9d5E68Ec105046FC4383` | `Curve.AddressProvider` |
| [Base](https://docs.eco.com/sauce-sdk/reference/chains/base.md) | routerNG | `0x4f37A9d177470499A2dD084621020b023fcffc1F` | `Curve.RouterNG` |
| [Arbitrum One](https://docs.eco.com/sauce-sdk/reference/chains/arbitrum.md) | addressProvider | `0x0000000022D53366457F9d5E68Ec105046FC4383` | `Curve.AddressProvider` |
| [Arbitrum One](https://docs.eco.com/sauce-sdk/reference/chains/arbitrum.md) | routerNG | `0x2191718CD32d02B8E60BAdFFeA33E4B5DD9A0A0D` | `Curve.RouterNG` |
| [Avalanche C-Chain](https://docs.eco.com/sauce-sdk/reference/chains/avalanche.md) | addressProvider | `0x0000000022D53366457F9d5E68Ec105046FC4383` | `Curve.AddressProvider` |

## 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

* [Protocols](https://docs.eco.com/sauce-sdk/reference/protocols.md): the other protocols, by what they do.
* [Protocols and tokens](https://docs.eco.com/sauce/names.md): calling a contract by its namespace, or through its ABI.
* [Glossary](https://docs.eco.com/sauce/glossary.md): the words these pages use, in plain terms.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.