Production-grade USDC/USDT StableSwap pool on Base mainnet — MIT licensed, open source, forkable.
Built by Fluid Wallet · Auditable math · Deploy in one command
A StableSwap AMM (like Curve Finance) for stablecoins on Base. It uses the Curve invariant to provide:
- Near-zero slippage for USDC↔USDT swaps
- 4 bps (0.04%) swap fee — among the lowest available
- 50% admin fee → Fluid treasury
- A=100 amplification factor — optimal for pegged assets
A·n^n·(x + y) + D = A·n^n·D + D^(n+1) / (n^n · x · y)
Simplified for n=2:
4A(x + y) + D = 4AD + D³ / (4xy)
Where:
x,y= token reserves (scaled to 18 decimals)D= total liquidity invariant (computed via Newton-Raphson)A= amplification factor (100 for stablecoins)
Key property: As A → ∞, the curve approaches a constant-sum (x+y=D) with zero slippage. As A → 0, it approaches Uniswap's constant-product (xy=k). A=100 is the sweet spot.
D_{n+1} = (Ann·S/A_PREC + D_P·N) · D_n / ((Ann - A_PREC)·D_n/A_PREC + (N+1)·D_P)
Where D_P = D³ / (N^N · x₀ · x₁), iterated until |D_{n+1} - D_n| ≤ 1.
| Contract | Description |
|---|---|
StableMath.sol |
Pure math library: getD(), getY(), calculateWithdrawOneCoin() |
StableAMM.sol |
Main pool: swap, addLiquidity, removeLiquidity |
StableAMMFactory.sol |
Factory: deploy pools for any token pair |
LPToken.sol |
ERC-20 LP token (minted/burned only by pool) |
IStableAMM.sol |
Interface for integrators |
nonReentranton all state-changing functions (OpenZeppelin)minOut/ slippage protection on every user-facing functiondeadlineparameter onswap()prevents stale transactions- Admin-gated:
rampA,collectAdminFees,pause,transferAdmin - Newton-Raphson capped at 255 iterations with convergence check
- All math in
uint256, no unsafe casting - Linear A-ramping with 10x max change per ramp (safe migration)
fluid-stable-amm/
├── src/
│ ├── StableAMM.sol # Main pool
│ ├── StableAMMFactory.sol # Factory
│ ├── LPToken.sol # ERC-20 LP token
│ ├── libraries/
│ │ └── StableMath.sol # Pure math
│ └── interfaces/
│ └── IStableAMM.sol # Interface
├── test/
│ ├── StableAMM.t.sol # Fork tests (Base mainnet)
│ └── StableMath.t.sol # Math unit tests
├── script/
│ ├── Deploy.s.sol # Deploy pool + factory
│ └── DeployFactory.s.sol # Deploy factory only
├── sdk/
│ └── src/
│ ├── index.ts # Re-exports
│ ├── pool.ts # StableAMMPool class
│ ├── math.ts # Off-chain math (BigInt)
│ └── types.ts # TypeScript types
├── foundry.toml
└── .env.example
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Install OpenZeppelin
forge install OpenZeppelin/openzeppelin-contractsgit clone https://github.com/fluidwallet/fluid-stable-amm
cd fluid-stable-amm
forge build# Math unit tests (no RPC needed)
forge test --match-contract StableMathTest -vvv
# Fork tests (requires BASE_RPC_URL)
cp .env.example .env
# Fill in BASE_RPC_URL
forge test --fork-url $BASE_RPC_URL -vvvcp .env.example .env
# Fill in PRIVATE_KEY, BASE_RPC_URL, BASESCAN_API_KEY
forge script script/Deploy.s.sol \
--rpc-url base \
--broadcast \
--verify \
--etherscan-api-key $BASESCAN_API_KEYExpected cost: ~$0.10–$0.50 on Base mainnet.
npm install @fluid-stable-amm/sdk viemimport { StableAMMPool } from "@fluid-stable-amm/sdk";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";
const client = createPublicClient({ chain: base, transport: http() });
const pool = new StableAMMPool(
{
poolAddress: "0x...", // deployed pool
token0: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
token1: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2", // USDT
lpToken: "0x...",
ampFactor: 100n,
swapFee: 4n,
adminFee: 5000n,
},
client
);
// Get pool stats
const stats = await pool.getPoolStats();
console.log("TVL:", stats.reserve0 + stats.reserve1);
// Off-chain quote (instant, no RPC)
const quote = pool.quoteSwap(1000_000000n, 0, stats.reserve0, stats.reserve1);
console.log("Get:", quote.amountOut, "USDT");
console.log("Fee:", quote.fee);
console.log("Price impact:", quote.priceImpact * 100, "%");Want to deploy your own USDC/USDT pool or a different pair? Just:
forge script script/Deploy.s.sol \
--rpc-url <your-rpc> \
--broadcast \
--verifyOr deploy via the factory for any ERC-20 pair:
StableAMMFactory factory = StableAMMFactory(FACTORY_ADDRESS);
address myPool = factory.deployPool(
TOKEN_A,
TOKEN_B,
100, // A factor
4 // 0.04% fee
);| Token | Address |
|---|---|
| USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| USDT | 0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2 |
MIT — do whatever you want. Fork it, deploy it, build on it.
Built by Fluid Wallet · Report issues