-
-
Notifications
You must be signed in to change notification settings - Fork 260
feat: add split routing in Uniswap and Pancakeswap quote-swap #568
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: fix/restart-race-condition
Are you sure you want to change the base?
feat: add split routing in Uniswap and Pancakeswap quote-swap #568
Conversation
- Add AlphaRouterService for smart order routing across V2/V3 pools - Update quoteSwap to use AlphaRouter instead of UniversalRouterQuote - Pass slippagePct parameter through to AlphaRouter - Upgrade @uniswap/smart-order-router to v4.22.38 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add maximumSplits config option to pancakeswap.yml - Pass maxHops and maxSplits from config to SmartRouter.getBestTrade() - Update Uniswap quoteSwap test to use AlphaRouterQuoteResult mock format 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…Router For EXACT_OUTPUT trades, the AlphaRouter's route() method expects the quoteCurrency to be the input token (what we pay), not the output token. The previous code always passed tokenOut, which caused "Invariant failed: ADDRESSES" errors when getting BUY quotes because the V4 pool provider tried to compare a token with itself. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…tions - handleTransactionExecution now returns null for pending transactions instead of a fake receipt with status:0 (which means reverted in ethers) - handleExecuteQuoteTransactionConfirmation now accepts txHash parameter to return the transaction hash for pending transactions - Fixed status code mapping to match Hummingbot's TransactionStatus: - CONFIRMED = 1 - PENDING = 0 - FAILED = -1 - Track txHash immediately after sending transaction in executeQuote Previously, pending transactions were incorrectly marked as failed because the fake receipt had status:0, which in Ethereum means the transaction reverted on-chain. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Move detailed AlphaRouter and quoteSwap logs from info to debug level, keeping only essential messages at info for cleaner production logs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
nikspz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- commit bf2e374
- Cloned and installed gw658 and client latest development branch
- set up gateway so gateway ONLINE
- Uniswap quote-swap with various token pairs on mainnet
- GET /connectors/uniswap/router/quote-swap
- default NodeURL, error 500 ❌
- changed nodeURL to infura ✅
- Basic Quote Test ✅
- curl -X'GET'
'http://localhost:15888/connectors/uniswap/router/quote-swap?network=mainnet&baseToken=WETH"eToken=USDC&amount=0.01&side=SELL&slippagePct=2&walletAddress=0x08940dc9b5a19fab9319b77c61dda7b8067e6843'
-H'accept: application/json'- {
"quoteId":"2881f544-97c6-4b9e-a46c-d64e0265caf0",
"tokenIn":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"tokenOut":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"amountIn":0.01,
"amountOut":29.320486,
"price":2932.0485999999996,
"priceImpactPct":0.01036,
"minAmountOut":28.73407628,
"maxAmountIn":0.01,
"routePath":"100% via WETH -> USDC"
}
- {
- curl -X'GET'
- Different Slippage Settings ✅
- review minAmountOut changes according to different Slippage set ✅
- Large Amount Split Routing ✅
- Review Using a large trade order amount lead to split routing ✅
- Gas Estimation Visibility
- returned quote response Not includes a gas estimate field. ❌
- GET /connectors/uniswap/router/quote-swap
- PancakeSwap quote-swap on BSC
- changed bsc nodeURL to https://bsc-dataseed4.binance.org/
- GET /connectors/pancakeswap/router/quote-swap
- Default Configuration ✅
- curl -X 'GET'
'http://localhost:15888/connectors/pancakeswap/router/quote-swap?network=bsc&baseToken=USDT"eToken=WBNB&amount=10&side=BUY&slippagePct=2&walletAddress=0x08940dc9b5a19fab9319b77c61dda7b8067e6843'
-H 'accept: application/json'- {
"quoteId":"fb52f3ca-ef3f-42c4-9331-9adc59ba938d",
"tokenIn":"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
"tokenOut":"0x55d398326f99059fF775485246999027B3197955",
"amountIn":0.011616003503498944,
"amountOut":10,
"price":860.8812830495294,
"priceImpactPct":1.1616e-21,
"minAmountOut":10,
"maxAmountIn":0.011848323573568922,
"routePath":"WBNB -> USDT"
}- correct amount
- {
- gateway config pancakeswap
- Gateway Configuration default pancakeswap: ✅
- slippagePct: 2
- maximumHops: 4
- maximumSplits: 4
- Vary maximumHops and Vary maximumSplits
- maximumHops 3 ❌
- maximumHops 1 LINK-WBNB ✅
- Slippage Respect ✅
- slippagePct is correctly respected and applied by PancakeSwap Smart Router
- minAmountOut changes proportionally with slippage tolerance, confirming correct slippage handling
- Gateway Configuration default pancakeswap: ✅
|
@nikspz there is no Gas Estimation in quote-swap response. Check the schema. Gas is handled by /solana/estimate-gas |
- Add intermediate token lists for each network (BSC, mainnet, arbitrum, base) - Refactor pool discovery to search for pools through intermediate tokens - Enable multi-hop routes like LINK -> WBNB -> DAI - maximumHops and maximumSplits config options now work correctly - Fixes "No routes found" error for token pairs without direct pools 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
failed to found route when you need to use workaround for no pool:
example LINK-DAI should use 2 swaps LINK → WBNB → DAI and actual is below
- commit f4e465c
- Uniswap quote-swap with various token pairs on mainnet
- GET /connectors/uniswap/router/quote-swap
- changed nodeURL to infura
- Basic Quote Test ✅
- curl -X'GET'
'http://localhost:15888/connectors/uniswap/router/quote-swap?network=mainnet&baseToken=WETH"eToken=USDC&amount=0.001&side=BUY&slippagePct=2&walletAddress=0x08940dc9b5a19fab9319b77c61dda7b8067e6843'
-H'accept: application/json'- {
"quoteId":"8862d95c-4df4-44b9-9f6d-4e24131ccbff",
"tokenIn":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"tokenOut":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"amountIn":2.973377,
"amountOut":0.001,
"price":2973.377,
"priceImpactPct":0.01008,
"minAmountOut":0.001,
"maxAmountIn":3.03284454,
"routePath":"100% via USDC -> WETH"
}
- {
- curl -X'GET'
- Different Slippage Settings ✅
- review minAmountOut changes according to different Slippage set ✅
- Large Amount Split Routing ✅
- Review Using a large trade order amount lead to split routing ✅
- Gas Estimation ✅
- /chains/ethereum/estimate-gas: gas price is very low but structurally valid
- /chains/solana/estimate-gas: Includes base fee + CU fee, expected
- PancakeSwap quote-swap on BSC
- GET /connectors/pancakeswap/router/quote-swap ✅
- Default Configuration ✅
- curl -X'GET'
'http://localhost:15888/connectors/pancakeswap/router/quote-swap?network=bsc&baseToken=USDT"eToken=WBNB&amount=10&side=SELL&slippagePct=2&walletAddress=0x08940dc9b5a19fab9319b77c61dda7b8067e6843'
-H'accept: application/json'- {
"quoteId":"ce7a22a7-1854-47e0-932a-9f427d814333",
"tokenIn":"0x55d398326f99059fF775485246999027B3197955",
"tokenOut":"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
"amountIn":10,
"amountOut":0.011734879464878443,
"price":0.0011734879464878442,
"priceImpactPct":8.5216e-16,
"minAmountOut":0.011500181875580873,
"maxAmountIn":10,
"routePath":"USDT -> WBNB"
}
- {
- curl -X'GET'
- gateway config pancakeswap
- Gateway Configuration default pancakeswap:
- slippagePct: 2
- maximumHops: 4
- maximumSplits: 4
- Vary maximumHops and Vary maximumSplits
- maximumHops 3
- changed pair to LINK-DAI
-
Example Expected
Multi-hop (no splits)
LINK → WBNB → DAIMulti-hop + split routing
60% LINK → WBNB → DAI 40% LINK → BUSD → DAI -
Actual result:
"routePath": "LINK -> DAI -> LINK -> DAI -> LINK -> DAI"❌- no hop explained in the response
- {
"quoteId":"df2a5471-5730-44dd-8ebd-397f751db06b",
"tokenIn":"0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD",
"tokenOut":"0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3",
"amountIn":10,
"amountOut":119.61994163452825,
"price":11.961994163452825,
"priceImpactPct":8.35981e-20,
"minAmountOut":117.22754280183769,
"maxAmountIn":10,
"routePath":"LINK -> DAI -> LINK -> DAI -> LINK -> DAI"
} - However gateway logs contains possible solutions
-
- logs:
- 2025-12-29 04:18:07 | info | [quoteSwap] Starting quote generation 19:18:07 [36/620]2025-12-29 04:18:07 | info | [quoteSwap] Network: bsc, Wallet: 0x08940dc9b5a19fab9319b77c61dda7b8067e6843 2025-12-29 04:18:07 | info | [quoteSwap] Base: LINK, Quote: DAI 2025-12-29 04:18:07 | info | [quoteSwap] Amount: 10, Side: SELL, Slippage: 2% 2025-12-29 04:18:07 | info | Pancakeswap connector initialized for network: bsc 2025-12-29 04:18:07 | info | [quoteSwap] Base token: LINK (0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD) 2025-12-29 04:18:07 | info | [quoteSwap] Quote token: DAI (0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3) 2025-12-29 04:18:07 | info | [quoteSwap] Input token: LINK (0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD) 2025-12-29 04:18:07 | info | [quoteSwap] Output token: DAI (0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3) 2025-12-29 04:18:07 | info | [quoteSwap] Exact in: true 2025-12-29 04:18:07 | info | [quoteSwap] Calling getUniversalRouterQuote... 2025-12-29 04:18:07 | info | [UniversalRouter] Starting quote generation 2025-12-29 04:18:07 | info | [UniversalRouter] Input: 10 LINK (0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD) 2025-12-29 04:18:07 | info | [UniversalRouter] Output: DAI (0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3) 2025-12-29 04:18:07 | info | [UniversalRouter] Trade type: EXACT_INPUT 2025-12-29 04:18:07 | info | [UniversalRouter] Recipient: 0x08940dc9b5a19fab9319b77c61dda7b8067e6843 2025-12-29 04:18:07 | info | [UniversalRouter] Slippage: 2% 2025-12-29 04:18:07 | info | [UniversalRouter] Max hops: 3 2025-12-29 04:18:07 | info | [UniversalRouter] Max splits: 4 2025-12-29 04:18:07 | info | [UniversalRouter] Protocols to check: 0, 1 2025-12-29 04:18:07 | info | [UniversalRouter] Using 4 intermediate tokens for multi-hop routing: WBNB, USDT, USDC, BUSD 2025-12-29 04:18:07 | info | [UniversalRouter] Searching 9 token pairs for pools... 2025-12-29 04:18:07 | info | [UniversalRouter] Searching for V3 pools...
- 2025-12-29 04:18:09 | info | [UniversalRouter] Found V3 pool: LINK <-> WBNB 2025-12-29 04:18:10 | info | [UniversalRouter] Found V3 pool: WBNB <-> DAI 2025-12-29 04:18:10 | info | [UniversalRouter] Found V3 pool: LINK <-> USDT 2025-12-29 04:18:11 | info | [UniversalRouter] Found V3 pool: USDT <-> DAI 2025-12-29 04:18:13 | info | [UniversalRouter] Found V3 pool: USDC <-> DAI 2025-12-29 04:18:12 | info | [UniversalRouter] Found V3 pool: BUSD <-> DAI 2025-12-29 04:18:12 | info | [UniversalRouter] Searching for V2 pools... 2025-12-29 04:18:12 | info | [UniversalRouter] Found V2 pool: LINK <-> WBNB 2025-12-29 04:18:13 | info | [UniversalRouter] Found V2 pool: WBNB <-> DAI 2025-12-29 04:18:13 | info | [UniversalRouter] Found V2 pool: LINK <-> USDT 2025-12-29 04:18:13 | info | [UniversalRouter] Found V2 pool: USDT <-> DAI 2025-12-29 04:18:13 | info | [UniversalRouter] Found V2 pool: LINK <-> USDC 2025-12-29 04:18:14 | info | [UniversalRouter] Found V2 pool: USDC <-> DAI 2025-12-29 04:18:14 | info | [UniversalRouter] Found V2 pool: LINK <-> BUSD 2025-12-29 04:18:14 | info | [UniversalRouter] Found V2 pool: BUSD <-> DAI 2025-12-29 04:18:14 | info | [UniversalRouter] Total pools found: 14
- 2025-12-29 04:18:15 | info | [UniversalRouter] Building swap parameters... Warning: 0x08940dc9b5a19fab9319b77c61dda7b8067e6843 is not checksummed. 2025-12-29 04:18:15 | info | [UniversalRouter] Calldata length: 2698, Value: 0x00 2025-12-29 04:18:15 | info | [UniversalRouter] Route path: LINK -> DAI -> LINK -> DAI -> LINK -> DAI 2025-12-29 04:18:15 | info | [UniversalRouter] Skipping gas estimation for quote (will estimate during execution) 2025-12-29 04:18:15 | info | [UniversalRouter] Quote generation complete 2025-12-29 04:18:15 | info | [UniversalRouter] Input: 10 LINK 2025-12-29 04:18:15 | info | [UniversalRouter] Output: 119.619941634528239847 DAI 2025-12-29 04:18:15 | info | [UniversalRouter] Price Impact: 8.35981e-20% 2025-12-29 04:18:15 | info | [quoteSwap] Quote result received 2025-12-29 04:18:15 | info | [quoteSwap] Generated quote ID: df2a5471-5730-44dd-8ebd-397f751db06b 2025-12-29 04:18:15 | info | [quoteSwap] Route path: LINK -> DAI -> LINK -> DAI -> LINK -> DAI 2025-12-29 04:18:15 | info | [quoteSwap] Estimated amounts - In: 10, Out: 119.61994163452825 2025-12-29 04:18:15 | info | [quoteSwap] Price: 11.961994163452825, Min out: 117.22754280183769, Max in: 10 2025-12-29 04:18:15 | info | [quoteSwap] Cached quote df2a5471-5730-44dd-8ebd-397f751db06b: 10 LINK -> 119.61994163452825 DAI 2025-12-29 04:18:15 | info | [quoteSwap] Method parameters available: true 2025-12-29 04:18:15 | info | [quoteSwap] Calldata length: 2698 2025-12-29 04:18:15 | info | [quoteSwap] Value: 0x00 2025-12-29 04:18:15 | info | [quoteSwap] To: 0x13f4EA83D0bd40E75C8222255bc855a974568Dd4
-
-
another attempts:
- 2025-12-29 04:31:28 | error | Error getting quote: Cannot find a valid swap route {} ❌
- {
"statusCode":500,
"error":"HttpError",
"message":"Cannot find a valid swap route"
}
-
- changed pair to LINK-DAI
- maximumHops 1 LINK-WBNB ✅
- maximumHops 3
- Slippage Respect
- slippagePct is correctly respected and applied by PancakeSwap Smart Router
- minAmountOut changes proportionally with slippage tolerance, confirming correct slippage handling
- Gateway Configuration default pancakeswap:
- Default Configuration ✅
- GET /connectors/pancakeswap/router/quote-swap ✅
- GET /connectors/uniswap/router/quote-swap
- Uniswap quote-swap with various token pairs on mainnet
- Fix extractRoutePath to use route.path array which contains all tokens including intermediates (e.g., LINK -> WBNB -> DAI) - Add percentage display for split routes (e.g., "50% via LINK -> WBNB -> DAI") - Change route join separator from ' -> ' to ', ' for multiple split routes - Add tests to verify routePath format includes percentage and token path Before: "LINK -> DAI -> LINK -> DAI -> LINK -> DAI" (wrong) After: "100% via LINK -> WBNB -> DAI" (correct) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>


Summary
/quote-swapendpointmaxHopsandmaxSplitssupport to PancakeSwap Smart Router for split routingChanges
Uniswap AlphaRouter Integration
@uniswap/smart-order-routergetAlphaRouterQuote()method with slippage passthrough@uniswap/smart-order-routerto v4.22.38PancakeSwap Smart Router Split Routing
maximumSplitsconfig option (default: 4)maximumSplitsto config interfacemaxHopsandmaxSplitstoSmartRouter.getBestTrade()getUniversalRouterQuote()Features
maximumHopsandmaximumSplitsfor route optimizationExample Response
{ "quoteId": "645a6983-3d59-4334-bd60-410a6ba13eac", "tokenIn": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "tokenOut": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "amountIn": 0.1, "amountOut": 319.60517, "price": 3196.05, "priceImpactPct": 0.01415, "routePath": "100% via WETH -> USDC" }Test plan