@lendliq/router
v1.0.0
Published
DEX routing and path finding for LendLiq protocol
Maintainers
Readme
@lendliq/router
DEX routing and path finding for LendLiq protocol. Works with @lendliq/sdk for core entities.
Installation
npm install @lendliq/router @lendliq/sdk viem
# or
yarn add @lendliq/router @lendliq/sdk viem
# or
pnpm add @lendliq/router @lendliq/sdk viemQuick Start
import { PathFinder } from "@lendliq/router";
import { Token, Trade, Route } from "@lendliq/sdk";
import { createPublicClient, http } from "viem";
import { bsc } from "viem/chains";
import { BigNumber } from "bignumber.js";
// 1. Define your tokens
const WBNB = new Token(56, "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", 18, "WBNB");
const USDT = new Token(56, "0x55d398326f99059fF775485246999027B3197955", 18, "USDT");
const ETH = new Token(56, "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", 18, "ETH");
// 2. Create viem client
const client = createPublicClient({
chain: bsc,
transport: http()
});
// 3. Initialize PathFinder (once at app startup)
const pathFinder = await PathFinder.create({
chainId: 56,
client,
v3Factory: "0xdB1d10011AD0Ff90774D0C6Bb92e5C5c8b4461F7",
tokens: [WBNB, USDT, ETH],
feeTiers: [500, 2500, 10000],
});
// 4. Find best route (no need to pass config again!)
const result = await pathFinder.findBestRoute(
USDT.address,
ETH.address,
new BigNumber("100000000000000000000") // 100 USDT
);
if (result) {
console.log(`Output: ${result.amountOut.toString()}`);
console.log(`Price Impact: ${result.priceImpact}%`);
console.log(`Routes: ${result.routes.length}`);
// Create Trade object for execution
const routes = result.routes.map(r =>
new Route(r.steps, r.expectedOutput, r.priceImpact, r.percentage)
);
const trade = new Trade(USDT, ETH, amountIn, result.amountOut, routes, result.priceImpact);
// Get params for smart contract
const params = trade.toAggregatorParams(userAddress, 50); // 0.5% slippage
}Setup Configuration
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| chainId | number | Yes | - | Chain ID (e.g., 56 for BSC) |
| client | PublicClient | Yes | - | Viem public client |
| v3Factory | string | Yes | - | V3 factory contract address |
| tokens | Token[] | Yes | - | Token list for pool discovery |
| quoter | string | No | - | Optional Quoter contract address |
| feeTiers | number[] | No | [500, 2500, 10000] | Fee tiers to search (basis points) |
| maxHops | number | No | 3 | Maximum hops in a route |
| maxRoutes | number | No | 5 | Maximum routes to consider |
| enableSplitRouting | boolean | No | true | Enable split routing |
| maxSplitRoutes | number | No | 3 | Maximum routes to split across |
| minSplitPercentage | number | No | 500 | Minimum percentage per split (5%) |
| multicallBatchSize | number | No | 100 | Batch size for multicall requests |
API
PathFinder.create(config)
Create and initialize a new PathFinder instance. Discovers all pools between provided tokens.
const pathFinder = await PathFinder.create({
chainId: 56,
client,
v3Factory: "0x...",
tokens: [WBNB, USDT, ETH, BUSD],
feeTiers: [500, 2500, 10000],
});pathFinder.findBestRoute(tokenIn, tokenOut, amountIn, options?)
Find the best route for a swap. Configuration from setup is used automatically.
const result = await pathFinder.findBestRoute(
USDT.address,
ETH.address,
new BigNumber("100000000000000000000"),
{
// Optional overrides for this query
maxHops: 2,
disableSplitRouting: true,
}
);pathFinder.addTokens(tokens)
Add new tokens and discover their pools with existing tokens.
const CAKE = new Token(56, "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", 18, "CAKE");
await pathFinder.addTokens([CAKE]);pathFinder.refreshPools()
Refresh all pool data (prices, liquidity).
await pathFinder.refreshPools();pathFinder.setFeeTiers(feeTiers)
Update fee tiers and clear pool cache.
pathFinder.setFeeTiers([100, 500, 3000, 10000]);pathFinder.getDiscoveredPools()
Get all discovered pools.
const pools = pathFinder.getDiscoveredPools();
console.log(`Found ${pools.length} pools`);pathFinder.getCacheStats()
Get cache statistics.
const stats = pathFinder.getCacheStats();
console.log(`Pools: ${stats.pools}, Tokens: ${stats.tokens}`);Performance (Multicall)
PathFinder uses multicall for efficient batch RPC requests, significantly reducing initialization time:
// Without multicall: 10 tokens × 3 fee tiers = 135 pool queries = 135+ RPC calls
// With multicall: Same queries batched into ~3-4 RPC calls
// Example: 10 tokens with 3 fee tiers
// - Pool address queries: 1 multicall (45 calls batched)
// - Pool data queries: 1-2 multicalls (225 calls batched)
// - Token decimals: 1 multicall (if needed)Configure batch size based on your RPC provider limits:
const pathFinder = await PathFinder.create({
// ... other config
multicallBatchSize: 100, // Default: 100, adjust based on RPC limits
});Split Routing
For large trades, PathFinder automatically splits the trade across multiple routes to minimize price impact:
const result = await pathFinder.findBestRoute(tokenIn, tokenOut, largeAmount);
// result.routes might contain multiple routes:
// [
// { percentage: 6000, expectedOutput: "...", steps: [...] }, // 60%
// { percentage: 4000, expectedOutput: "...", steps: [...] }, // 40%
// ]Multi-Chain Support
Use the same API for different chains:
// BSC Mainnet
const bscPathFinder = await PathFinder.create({
chainId: 56,
client: bscClient,
v3Factory: "0x...",
tokens: bscTokens,
});
// BSC Testnet
const testnetPathFinder = await PathFinder.create({
chainId: 97,
client: testnetClient,
v3Factory: "0x...",
tokens: testnetTokens,
});
// Ethereum
const ethPathFinder = await PathFinder.create({
chainId: 1,
client: ethClient,
v3Factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984", // Uniswap V3
tokens: ethTokens,
feeTiers: [100, 500, 3000, 10000], // Uniswap fee tiers
});License
MIT
