Skip to content

Conversation

@fengtality
Copy link
Contributor

@fengtality fengtality commented Dec 4, 2025

Summary

  • Integrate Uniswap's AlphaRouter (smart-order-router) for split routing in /quote-swap endpoint
  • Enable optimal trade execution by routing across V2 and V3 pools with split percentages
  • Provides same routing capability as Uniswap web UI for better execution prices
  • Add maxHops and maxSplits support to PancakeSwap Smart Router for split routing

Changes

Uniswap AlphaRouter Integration

  • alpha-router.ts: New AlphaRouterService class wrapping @uniswap/smart-order-router
  • quoteSwap.ts: Updated to use AlphaRouter instead of basic UniversalRouter quote
  • uniswap.ts: Added getAlphaRouterQuote() method with slippage passthrough
  • package.json: Upgraded @uniswap/smart-order-router to v4.22.38

PancakeSwap Smart Router Split Routing

  • pancakeswap.yml: Added maximumSplits config option (default: 4)
  • pancakeswap.config.ts: Added maximumSplits to config interface
  • universal-router.ts: Pass maxHops and maxSplits to SmartRouter.getBestTrade()
  • pancakeswap.ts: Pass config values when calling getUniversalRouterQuote()

Features

  • Split routing across multiple pools (e.g., "60% via V3 0.3%, 40% via V2")
  • Automatic route optimization for better execution prices
  • Slippage tolerance now properly passed from request to router
  • Gas estimation in USD
  • PancakeSwap: Configurable maximumHops and maximumSplits for route optimization

Example 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

  • Test Uniswap quote-swap with various token pairs on mainnet
  • Verify slippagePct parameter is respected in logs
  • Test with larger amounts to verify split routing kicks in
  • Verify gas estimates are returned
  • Test PancakeSwap quote-swap on BSC
  • Verify PancakeSwap maxHops/maxSplits config is logged

- 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>
@fengtality fengtality added this to the dev-2.12 milestone Dec 4, 2025
- 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>
@fengtality fengtality changed the title feat: integrate AlphaRouter for split routing in Uniswap quote-swap feat: add split routing in Uniswap and Pancakeswap quote-swap Dec 4, 2025
fengtality and others added 6 commits December 3, 2025 17:48
🤖 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>
@fengtality fengtality marked this pull request as ready for review December 9, 2025 18:31
@rapcmia rapcmia requested a review from nikspz December 15, 2025 13:07
@rapcmia rapcmia moved this to Backlog in Pull Request Board Dec 15, 2025
@rapcmia rapcmia moved this from Backlog to Under Review in Pull Request Board Dec 16, 2025
Copy link
Contributor

@nikspz nikspz left a 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
    • 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&quoteToken=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 ❌
              • changed pair to LINK-DAI
                • Example Routes You Should Expect

                  Multi-hop (no splits)

                  LINK → WBNB → DAI
                  
                  

                  Multi-hop + split routing

                  60% LINK → WBNB → DAI
                  40% LINK → BUSD → DAI
                  
                  
                • Actual result:

                  • image
                  • {
                    "statusCode":500,
                    "error":"HttpError",
                    "message":"No routes found for LINK -> DAI"
                    }
            • maximumHops 1 LINK-WBNB ✅
              • image
          • Slippage Respect ✅
            • slippagePct is correctly respected and applied by PancakeSwap Smart Router
            • minAmountOut changes proportionally with slippage tolerance, confirming correct slippage handling

@fengtality
Copy link
Contributor Author

@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>
Copy link
Contributor

@nikspz nikspz left a 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
      • PancakeSwap quote-swap on BSC
        • GET /connectors/pancakeswap/router/quote-swap ✅
          • Default Configuration ✅
          • 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 → DAI
                    
                    

                    Multi-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
                    • image
                    • 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
                    • image
                  • 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"
                      }
              • 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

- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Under Review

Development

Successfully merging this pull request may close these issues.

3 participants