@summitx/swap-quote-engine v1.0.0
Swap Quote Engine
A standalone TypeScript library for DEX aggregation and swap quote calculations, extracted from the SummitX AMM interface. This library provides accurate swap quotes by implementing the same logic used in production, including V2, V3, and StableSwap pool calculations with real data from The Graph subgraphs and onchain sources.
Features
- Multi-Protocol Support: V2 (constant product), V3 (concentrated liquidity), and StableSwap pools
- Smart Routing: Finds optimal routes across multiple pools with up to 3 hops
- Split Routing: Splits large trades across multiple routes for better execution
- Accurate Calculations: Implements actual pool math including V3 tick crossing and StableSwap invariants
- OnChain Quotes: Fetches accurate quotes from onchain quoter contracts
- Gas Optimization: Estimates gas costs and optimizes routes based on gas efficiency
- Real Data Sources: Fetches pool data from The Graph subgraphs and onchain
- Type Safe: Full TypeScript support with comprehensive types
Installation
npm install
# or
yarn install
Quick Start
import {
SmartRouter,
PoolProvider,
ChainId,
TradeType,
createCurrencyAmount
} from 'swap-quote-engine';
// Define tokens
const USDC = {
chainId: ChainId.BASECAMP_TESTNET,
address: '0x4200000000000000000000000000000000000006',
decimals: 6,
symbol: 'USDC',
name: 'USD Coin'
};
const WETH = {
chainId: ChainId.BASECAMP_TESTNET,
address: '0x4200000000000000000000000000000000000006',
decimals: 18,
symbol: 'WETH',
name: 'Wrapped Ether'
};
// Initialize pool provider
const poolProvider = new PoolProvider({
chainId: ChainId.BASECAMP_TESTNET,
});
// Fetch pools from subgraph and onchain
const pools = await poolProvider.getPools(USDC, WETH);
// Create router
const router = new SmartRouter({
pools,
maxHops: 3,
maxSplits: 2,
nativeTokenPriceUSD: 2000,
});
// Get quote for 1000 USDC
const inputAmount = createCurrencyAmount(
{ ...USDC, isNative: false, isToken: true },
BigInt(1000 * 10 ** 6)
);
const trade = await router.getBestTrade({
tokenIn: USDC,
tokenOut: WETH,
amount: inputAmount,
tradeType: TradeType.EXACT_INPUT,
gasPriceWei: BigInt(30 * 10 ** 9), // 30 gwei
});
if (trade) {
console.log(`Best route: ${trade.inputAmount.toFixed()} USDC → ${trade.outputAmount.toFixed()} WETH`);
console.log(`Price impact: ${trade.priceImpact?.mul(100).toFixed(2)}%`);
console.log(`Gas cost: $${trade.gasEstimateUSD?.toFixed(2)}`);
}
Architecture
The library consists of several key components:
Pool Implementations
- V2Pool: Implements Uniswap V2 style constant product AMM (x * y = k)
- V3Pool: Implements concentrated liquidity with tick crossing logic
- StablePool: Implements StableSwap invariant for low-slippage stablecoin swaps
Routing Components
- RouteComputer: Finds all possible routes between tokens (up to maxHops)
- QuoteComputer: Calculates quotes for each route
- TradeOptimizer: Finds optimal split across multiple routes
- SmartRouter: Orchestrates the routing process
Data Providers
- PoolProvider: Fetches pool data from subgraphs and onchain
- OnChainQuoteProvider: Gets accurate quotes from quoter contracts
Pool Calculations
V2 Pools
Uses the constant product formula with 0.3% fee:
outputAmount = (inputAmount * 997 * outputReserve) / (inputReserve * 1000 + inputAmount * 997)
V3 Pools
Implements full tick crossing logic:
- Swaps within tick ranges using liquidity math
- Crosses ticks when price moves outside current range
- Accurately calculates fees and slippage
- Estimates gas based on ticks crossed
Stable Pools
Implements StableSwap invariant:
- Uses Newton's method to solve for D (invariant)
- Calculates Y for output amount
- Supports 2-4 token pools
- Optimized for stablecoin swaps
Advanced Usage
Using OnChain Quotes
const quoteProvider = new OnChainQuoteProvider({
chainId: ChainId.BASECAMP_TESTNET,
multicallChunkSize: 50,
});
const routes = [...]; // Your routes
const quotes = await quoteProvider.getQuotesExactIn(routes, inputAmount);
Custom Pool Filtering
const router = new SmartRouter({
pools,
allowedPoolTypes: [PoolType.V2, PoolType.V3], // Exclude stable pools
maxHops: 2,
maxSplits: 3,
});
Multi-Hop Routing
// The router automatically finds multi-hop routes
// For example: USDC → WETH → DAI
const trade = await router.getBestTrade({
tokenIn: USDC,
tokenOut: DAI,
amount: inputAmount,
tradeType: TradeType.EXACT_INPUT,
});
Supported Chains
- Ethereum (ChainId.ETHEREUM)
- BSC (ChainId.BSC)
- Base Camp (ChainId.BASECAMP_TESTNET)
- Polygon (ChainId.POLYGON)
- Arbitrum (ChainId.ARBITRUM)
- Base (ChainId.BASE)
- Goerli, BSC Testnet, Base Camp Testnet
Configuration
All chain-specific configuration is centralized in src/config/index.ts
. This includes:
- Factory addresses for V2/V3/Stable pools
- Subgraph endpoints
- Quoter contract addresses
- RPC endpoints
- Wrapped native token addresses
- Gas prices and native token prices
Adding New Chains
To add support for a new chain, simply add its configuration to src/config/index.ts
:
import { CHAIN_CONFIG, ChainId } from 'swap-quote-engine';
// Add your chain configuration
CHAIN_CONFIG[ChainId.YOUR_CHAIN] = {
name: 'Your Chain',
rpcUrl: 'https://your-rpc.com',
nativeCurrency: {
name: 'Your Token',
symbol: 'YTK',
decimals: 18,
},
contracts: {
v2Factory: '0x...',
v3Factory: '0x...',
multicall3: '0xcA11bde05977b3631167028862bE2a173976CA11',
wrappedNativeToken: '0x...',
// ... other contracts
},
subgraphs: {
v2: 'https://...',
v3: 'https://...',
},
defaultGasPrice: 1000000000n,
nativeTokenPriceUSD: 100,
};
See ADD_NEW_CHAIN_GUIDE.md for detailed instructions.
Testing
# Run all tests
npm test
# Run integration tests
npm test integration.test.ts
# Run with coverage
npm run test:coverage
Gas Estimation
The library provides accurate gas estimates:
- Base swap cost: 90,000 gas
- V2 pool: 60,000 gas
- V3 pool: 100,000 gas + tick crossing costs
- Stable pool: 80,000 gas
- Additional hop cost: 20,000 gas
- Split route overhead: 30,000 gas per split
Price Impact Calculation
Price impact is calculated by comparing: 1. Spot price from the first pool 2. Execution price of the trade 3. Weighted impact across all routes for splits
API Reference
SmartRouter
interface SmartRouterOptions {
pools: Pool[];
maxHops?: number; // Default: 3
maxSplits?: number; // Default: 1
allowedPoolTypes?: PoolType[];
nativeTokenPriceUSD?: number;
}
class SmartRouter {
getBestTrade(params: QuoteParams): Promise<Trade | null>
getQuote(params: QuoteParams): Promise<CurrencyAmount | null>
}
PoolProvider
interface PoolProviderOptions {
chainId: ChainId;
rpcUrl?: string;
subgraphUrl?: string;
}
class PoolProvider {
getPools(token0: Token, token1: Token): Promise<Pool[]>
getV2PoolsFromSubgraph(token0: Token, token1: Token): Promise<V2Pool[]>
getV3PoolsFromSubgraph(token0: Token, token1: Token): Promise<V3Pool[]>
getV2PoolOnChain(token0: Token, token1: Token): Promise<V2Pool | null>
getV3PoolOnChain(token0: Token, token1: Token, fee: number): Promise<V3Pool | null>
}
License
MIT
1 month ago