@real-wagmi/equilibra-sdk
v1.3.0
Published
SDK for the EquilibraSwap cubic-invariant AMM
Downloads
797
Readme
@real-wagmi/equilibra-sdk
SDK for the EquilibraSwap cubic-invariant AMM: offline quoting that matches the contracts bit-for-bit, route/trade construction and router calldata.
Install
$ yarn add @real-wagmi/equilibra-sdk @real-wagmi/sdk @real-wagmi/v2-sdk viemUsage
Robinhood chain as the example. Here's the full path: read a pool's state from chain, quote a WETH → USDG swap offline, and build a valid router transaction from the trade.
1. Prepare an on-chain provider
import { createPublicClient, http } from 'viem';
const publicClient = createPublicClient({
transport: http('https://rpc.mainnet.chain.robinhood.com'),
batch: { multicall: true },
});2. Resolve the pool address offline
Pool addresses derive from CREATE2 — no factory call needed:
import { computePoolAddress } from '@real-wagmi/equilibra-sdk';
import { robinhoodTokens } from '@real-wagmi/v2-sdk';
const weth = robinhoodTokens.weth;
const usdg = robinhoodTokens.usdg;
const poolAddress = computePoolAddress({
factory: FACTORY_ADDRESS,
tokenA: weth.address,
tokenB: usdg.address,
pairPoolIndex: 0,
implementation: POOL_IMPLEMENTATION_ADDRESS, // or initCodeHash directly
});3. Read the pool state and construct a Pool
import { Pool } from '@real-wagmi/equilibra-sdk';
import { equilibraPoolAbi } from './abis'; // your generated pool ABI
const [metadata, curve, fee, oracle, [reserve0, reserve1]] = await Promise.all([
publicClient.readContract({ address: poolAddress, abi: equilibraPoolAbi, functionName: 'getPoolMetadata' }),
publicClient.readContract({ address: poolAddress, abi: equilibraPoolAbi, functionName: 'getCurveParams' }),
publicClient.readContract({ address: poolAddress, abi: equilibraPoolAbi, functionName: 'getFeeConfig' }),
publicClient.readContract({ address: poolAddress, abi: equilibraPoolAbi, functionName: 'getOracleState' }),
publicClient.readContract({ address: poolAddress, abi: equilibraPoolAbi, functionName: 'getReserves' }),
]);
const pool = new Pool(weth, usdg, {
pairPoolIndex: metadata.pairPoolIndex,
aWad: curve.aWad,
lambdaWad: curve.lambdaWad,
baseFeeBps: BigInt(fee.baseFee),
feeRampBps: BigInt(fee.feeRampBps),
feeFloorBps: BigInt(fee.feeFloorBps),
protocolFeePercent: BigInt(fee.protocolFeePercent),
priceScaleWad: oracle.priceScaleWad,
reserve0,
reserve1,
});
// Marginal spot prices, decimals-aware:
pool.token0Price.toSignificant(6); // e.g. "4000" USDG per WETH
pool.token1Price.toSignificant(6); // e.g. "0.00025" WETH per USDG4. Quote a trade offline
Quotes reproduce the contract exactly — dynamic fee on the gross input, cubic curve on the clean part, protocol split:
import { Route, Trade } from '@real-wagmi/equilibra-sdk';
import { CurrencyAmount, TradeType } from '@real-wagmi/v2-sdk';
const route = new Route([pool], weth, usdg);
// Exact input: sell 1 WETH.
const trade = Trade.exactIn(route, CurrencyAmount.fromRawAmount(weth, 10n ** 18n));
trade.outputAmount.toSignificant(6); // what you receive
trade.executionPrice.toSignificant(6);
trade.priceImpact.toSignificant(4);
// Exact output: buy exactly 1000 USDG.
const exactOut = Trade.exactOut(route, CurrencyAmount.fromRawAmount(usdg, 1_000_000_000n));
exactOut.inputAmount.toSignificant(6); // what you must pay
// Or search routes over a pool set (multi-hop up to maxHops):
const best = Trade.bestTradeExactIn(allPools, CurrencyAmount.fromRawAmount(weth, 10n ** 18n), someToken, { maxHops: 3 });5. Build the swap transaction
import { SwapRouter } from '@real-wagmi/equilibra-sdk';
import { Percent } from '@real-wagmi/v2-sdk';
import { hexToBigInt } from 'viem';
const { calldata, value } = SwapRouter.swapCallParameters(trade, {
recipient: userAddress,
slippageTolerance: new Percent(5n, 1000n), // 0.5%
deadline: BigInt(Math.floor(Date.now() / 1000) + 1200),
});
const tx = {
account: userAddress,
to: ROUTER_ADDRESS,
data: calldata,
value: hexToBigInt(value),
};
const gasEstimate = await publicClient.estimateGas(tx);Native ETH works on both sides: use a native currency as the route
input/output — the SDK attaches value and batches
unwrapWETH9/refundETH through the router's payable multicall
automatically.
Attach value verbatim. It is exactly the sum of the legs'
maximumAmountIn under the given tolerance (and 0x0 for a non-native
input) — not a lower bound. The router's refundETH() is permissionless,
so any surplus you attach on top is claimable by the next account that
calls it. If the amount is uncertain, re-quote and rebuild the calldata,
or widen slippageTolerance (which raises value and keeps the appended
refundETH leg matched to it) — never pad the value.
6. Liquidity
import { LiquidityManager, LiquidityMath } from '@real-wagmi/equilibra-sdk';
// Preview the share math offline:
const { amount0, amount1 } = LiquidityMath.addAmounts(desired0, desired1, pool.reserve0, pool.reserve1);
const shares = LiquidityMath.sharesForAmounts(amount0, totalSupply, pool.reserve0);
// Router addLiquidity calldata (minShares derived under the tolerance):
const add = LiquidityManager.addCallParameters(pool, desired0, desired1, totalSupply, {
slippageTolerance: new Percent(5n, 1000n),
recipient: userAddress,
deadline,
});
// removeLiquidity is a DIRECT POOL call (the pool is its own LP token):
const remove = LiquidityManager.removeCallParameters(pool, sharesToBurn, {
slippageTolerance: new Percent(5n, 1000n),
recipient: userAddress,
totalSupply,
});
// send { to: poolAddress, data: remove.calldata }
// Single-sided zap through the router:
const zap = LiquidityManager.zapInSingleSidedCallParameters(pool, weth.address, amountIn, minShares, {
recipient: userAddress,
deadline,
});Layers
SwapMath/FullMath— the on-chainEquilibraSwapMathkernel ported verbatim: closed-form depth solve, the 12-iteration secant counterpart solver, CP-proxy dynamic-fee ramp, marginal price — with the contract's exact rounding on every step.Pool— immutable; every quote returns[amount, postTradePool].Route/Trade— v3-sdk-shaped, synchronous.SwapRouter/LiquidityManager/Multicall/Payments— calldata builders over the router's own semantics (path codec[token(20)][poolIndex(4)], zero-address custody sentinel).LiquidityMath— genesis geomean minus dead shares, proportional caps, pro-rata removal, zap sizing.
Notes
- Amounts are raw on-chain units (
bigint); prices and curve params are WAD-scaled (1e18). Primitives (Token,CurrencyAmount,Percent,Price),ChainIdand the chain tokens all come from@real-wagmi/v2-sdk— its facade re-exports the base-SDK primitives, so it is the only install you need. - The quoter models a single swap exactly. EMA/auto-repeg run AFTER a swap commits and only affect the NEXT trade's anchor — deliberately out of scope.
- Parity with the contracts is maintained by differential fuzzing against
the on-chain math harness and the live pools'
quoteExactIn/quoteExactOutduring development.
