# Multi-DEX Architecture Design **Date:** October 26, 2025 **Purpose:** Expand from UniswapV3-only to 5+ DEX protocols --- ## 🎯 Objective Enable the MEV bot to monitor and execute arbitrage across multiple DEX protocols simultaneously, increasing opportunities from ~5,000/day to ~50,000+/day. --- ## πŸ“Š Target DEXs (Priority Order) ### Phase 1: Core DEXs (Week 1) 1. **SushiSwap** - 2nd largest DEX on Arbitrum - Protocol: AMM (constant product) - Fee: 0.3% - Liquidity: $50M+ 2. **Curve Finance** - Best for stablecoins - Protocol: StableSwap (low slippage for similar assets) - Fee: 0.04% - Liquidity: $30M+ (USDC/USDT/DAI pools) 3. **Balancer** - Weighted pools - Protocol: Weighted AMM - Fee: Variable (0.1-10%) - Liquidity: $20M+ ### Phase 2: Native DEXs (Week 2) 4. **Camelot** - Native Arbitrum DEX - Protocol: AMM with ve(3,3) model - Fee: 0.3% - Liquidity: $15M+ 5. **Trader Joe** - V2 liquidity bins - Protocol: Concentrated liquidity bins - Fee: Variable - Liquidity: $10M+ ### Phase 3: Advanced (Week 3) 6. **Uniswap V2** - Still used for some pairs 7. **Ramses** - ve(3,3) model 8. **Chronos** - Concentrated liquidity --- ## πŸ—οΈ Architecture Design ### Current Architecture (UniswapV3 Only) ``` Arbitrum Monitor ↓ Parse Swap Events ↓ UniswapV3 Decoder ONLY ↓ Opportunity Detection ↓ Execution ``` **Problem:** Hardcoded to UniswapV3 ### New Architecture (Multi-DEX) ``` Arbitrum Monitor ↓ Parse Swap Events ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ↓ ↓ ↓ DEX Registry DEX Detector Event Router ↓ ↓ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Protocol-Specific Decoders β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ UniswapV3 β”‚ SushiSwapβ”‚ Curve β”‚ β”‚ Decoder β”‚ Decoder β”‚ Decoder β”‚ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ Cross-DEX Price Analyzer ↓ Multi-DEX Arbitrage Detection ↓ Multi-Path Optimizer ↓ Execution ``` --- ## πŸ”§ Core Components ### 1. DEX Registry **Purpose:** Central registry of all supported DEXs ```go // pkg/dex/registry.go type DEXProtocol string const ( UniswapV3 DEXProtocol = "uniswap_v3" UniswapV2 DEXProtocol = "uniswap_v2" SushiSwap DEXProtocol = "sushiswap" Curve DEXProtocol = "curve" Balancer DEXProtocol = "balancer" Camelot DEXProtocol = "camelot" TraderJoe DEXProtocol = "traderjoe" ) type DEXInfo struct { Protocol DEXProtocol Name string RouterAddress common.Address FactoryAddress common.Address Fee *big.Int // Default fee PricingModel PricingModel // ConstantProduct, StableSwap, Weighted Decoder DEXDecoder QuoteFunction QuoteFunction } type DEXRegistry struct { dexes map[DEXProtocol]*DEXInfo mu sync.RWMutex } func NewDEXRegistry() *DEXRegistry { registry := &DEXRegistry{ dexes: make(map[DEXProtocol]*DEXInfo), } // Register all DEXs registry.Register(&DEXInfo{ Protocol: UniswapV3, Name: "Uniswap V3", RouterAddress: common.HexToAddress("0xE592427A0AEce92De3Edee1F18E0157C05861564"), FactoryAddress: common.HexToAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984"), Fee: big.NewInt(3000), // 0.3% PricingModel: ConcentratedLiquidity, }) registry.Register(&DEXInfo{ Protocol: SushiSwap, Name: "SushiSwap", RouterAddress: common.HexToAddress("0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"), FactoryAddress: common.HexToAddress("0xc35DADB65012eC5796536bD9864eD8773aBc74C4"), Fee: big.NewInt(3000), // 0.3% PricingModel: ConstantProduct, }) // ... register others return registry } func (dr *DEXRegistry) Register(dex *DEXInfo) { dr.mu.Lock() defer dr.mu.Unlock() dr.dexes[dex.Protocol] = dex } func (dr *DEXRegistry) Get(protocol DEXProtocol) (*DEXInfo, bool) { dr.mu.RLock() defer dr.mu.RUnlock() dex, ok := dr.dexes[protocol] return dex, ok } func (dr *DEXRegistry) All() []*DEXInfo { dr.mu.RLock() defer dr.mu.RUnlock() dexes := make([]*DEXInfo, 0, len(dr.dexes)) for _, dex := range dr.dexes { dexes = append(dexes, dex) } return dexes } ``` ### 2. DEX Detector **Purpose:** Identify which DEX a swap event belongs to ```go // pkg/dex/detector.go type DEXDetector struct { registry *DEXRegistry addressMap map[common.Address]DEXProtocol // Router address β†’ Protocol } func NewDEXDetector(registry *DEXRegistry) *DEXDetector { detector := &DEXDetector{ registry: registry, addressMap: make(map[common.Address]DEXProtocol), } // Build address map for _, dex := range registry.All() { detector.addressMap[dex.RouterAddress] = dex.Protocol detector.addressMap[dex.FactoryAddress] = dex.Protocol } return detector } func (dd *DEXDetector) DetectDEX(poolAddress common.Address) (DEXProtocol, error) { // 1. Check if we know this pool address if protocol, ok := dd.addressMap[poolAddress]; ok { return protocol, nil } // 2. Query pool's factory factoryAddress, err := dd.getPoolFactory(poolAddress) if err != nil { return "", err } // 3. Match factory to DEX if protocol, ok := dd.addressMap[factoryAddress]; ok { // Cache for future lookups dd.addressMap[poolAddress] = protocol return protocol, nil } return "", fmt.Errorf("unknown DEX for pool %s", poolAddress.Hex()) } ``` ### 3. Protocol-Specific Decoders **Purpose:** Each DEX has unique swap signatures and pricing models ```go // pkg/dex/decoder.go type DEXDecoder interface { // DecodeSwap parses a swap transaction for this DEX DecodeSwap(tx *types.Transaction) (*SwapInfo, error) // GetPoolReserves fetches current pool state GetPoolReserves(ctx context.Context, poolAddress common.Address) (*PoolReserves, error) // CalculateOutput computes output for given input CalculateOutput(amountIn *big.Int, reserves *PoolReserves) (*big.Int, error) } type SwapInfo struct { Protocol DEXProtocol Pool common.Address TokenIn common.Address TokenOut common.Address AmountIn *big.Int AmountOut *big.Int MinAmountOut *big.Int Recipient common.Address } type PoolReserves struct { Token0 common.Address Token1 common.Address Reserve0 *big.Int Reserve1 *big.Int Fee *big.Int // UniswapV3 specific SqrtPriceX96 *big.Int Liquidity *big.Int Tick int } // Example: SushiSwap Decoder type SushiSwapDecoder struct { client *ethclient.Client logger *logger.Logger } func (sd *SushiSwapDecoder) DecodeSwap(tx *types.Transaction) (*SwapInfo, error) { // SushiSwap uses same ABI as UniswapV2 // Function signature: swapExactTokensForTokens(uint,uint,address[],address,uint) data := tx.Data() if len(data) < 4 { return nil, fmt.Errorf("invalid transaction data") } methodID := data[:4] expectedID := crypto.Keccak256([]byte("swapExactTokensForTokens(uint256,uint256,address[],address,uint256)"))[:4] if !bytes.Equal(methodID, expectedID) { return nil, fmt.Errorf("not a swap transaction") } // Decode parameters params, err := sd.decodeSwapParameters(data[4:]) if err != nil { return nil, err } return &SwapInfo{ Protocol: SushiSwap, TokenIn: params.path[0], TokenOut: params.path[len(params.path)-1], AmountIn: params.amountIn, MinAmountOut: params.amountOutMin, Recipient: params.to, }, nil } func (sd *SushiSwapDecoder) CalculateOutput(amountIn *big.Int, reserves *PoolReserves) (*big.Int, error) { // x * y = k formula // amountOut = (amountIn * 997 * reserve1) / (reserve0 * 1000 + amountIn * 997) numerator := new(big.Int).Mul(amountIn, big.NewInt(997)) numerator.Mul(numerator, reserves.Reserve1) denominator := new(big.Int).Mul(reserves.Reserve0, big.NewInt(1000)) amountInWithFee := new(big.Int).Mul(amountIn, big.NewInt(997)) denominator.Add(denominator, amountInWithFee) amountOut := new(big.Int).Div(numerator, denominator) return amountOut, nil } ``` ### 4. Cross-DEX Price Analyzer **Purpose:** Find price discrepancies across DEXs ```go // pkg/dex/cross_dex_analyzer.go type CrossDEXAnalyzer struct { registry *DEXRegistry cache *PriceCache logger *logger.Logger } type PriceFeed struct { Protocol DEXProtocol Pool common.Address Token0 common.Address Token1 common.Address Price *big.Float // Token1 per Token0 Liquidity *big.Int LastUpdated time.Time } func (cda *CrossDEXAnalyzer) FindArbitrageOpportunities( tokenA, tokenB common.Address, ) ([]*CrossDEXOpportunity, error) { opportunities := make([]*CrossDEXOpportunity, 0) // 1. Get prices for tokenA/tokenB across all DEXs prices := cda.getPricesAcrossDEXs(tokenA, tokenB) // 2. Find price discrepancies for i, buyDEX := range prices { for j, sellDEX := range prices { if i == j { continue } // Buy on buyDEX, sell on sellDEX priceDiff := new(big.Float).Sub(sellDEX.Price, buyDEX.Price) priceDiff.Quo(priceDiff, buyDEX.Price) profitPercent, _ := priceDiff.Float64() // Is there arbitrage opportunity? if profitPercent > 0.003 { // > 0.3% opp := &CrossDEXOpportunity{ BuyDEX: buyDEX.Protocol, SellDEX: sellDEX.Protocol, TokenIn: tokenA, TokenOut: tokenB, BuyPrice: buyDEX.Price, SellPrice: sellDEX.Price, PriceDiff: profitPercent, EstimatedProfit: cda.calculateProfit(buyDEX, sellDEX), } opportunities = append(opportunities, opp) } } } return opportunities, nil } ``` --- ## πŸ”„ Multi-Hop Path Finding ### Algorithm: Bellman-Ford with Negative Cycle Detection ```go // pkg/arbitrage/pathfinder.go type PathFinder struct { registry *DEXRegistry graph *TokenGraph } type TokenGraph struct { // edges[tokenA][tokenB] = []Edge (all pools connecting A to B) edges map[common.Address]map[common.Address][]*Edge } type Edge struct { Protocol DEXProtocol Pool common.Address TokenFrom common.Address TokenTo common.Address Fee *big.Int Liquidity *big.Int Rate *big.Float // Exchange rate } func (pf *PathFinder) FindArbitragePaths( startToken common.Address, maxHops int, ) ([]*ArbitragePath, error) { paths := make([]*ArbitragePath, 0) // Use DFS to find all cycles starting from startToken visited := make(map[common.Address]bool) currentPath := make([]*Edge, 0, maxHops) pf.dfs(startToken, startToken, currentPath, visited, maxHops, &paths) return paths, nil } func (pf *PathFinder) dfs( current, target common.Address, path []*Edge, visited map[common.Address]bool, remaining int, results *[]*ArbitragePath, ) { // Base case: back to start token if len(path) > 0 && current == target { // Found a cycle! Calculate profitability profit := pf.calculatePathProfit(path) if profit > 0 { *results = append(*results, &ArbitragePath{ Edges: path, Profit: profit, }) } return } // Max hops reached if remaining == 0 { return } // Mark as visited visited[current] = true defer func() { visited[current] = false }() // Explore all neighbors for nextToken, edges := range pf.graph.edges[current] { // Skip if already visited (prevent loops) if visited[nextToken] { continue } // Try each DEX/pool connecting current to nextToken for _, edge := range edges { newPath := append(path, edge) pf.dfs(nextToken, target, newPath, visited, remaining-1, results) } } } ``` --- ## πŸ“ˆ Expected Performance ### Before Multi-DEX ``` DEXs Monitored: 1 (UniswapV3) Opportunities/day: 5,058 Profitable: 0 Daily Profit: $0 ``` ### After Multi-DEX (Week 1) ``` DEXs Monitored: 3 (Uniswap, Sushi, Curve) Opportunities/day: 15,000+ Profitable: 50-100/day Daily Profit: $50-$500 ``` ### After Multi-DEX + Multi-Hop (Week 2) ``` DEXs Monitored: 5+ Hops: 2-4 Opportunities/day: 50,000+ Profitable: 100-200/day Daily Profit: $200-$2,000 ``` --- ## πŸš€ Implementation Phases ### Phase 1.1: Core Infrastructure (Days 1-2) - [ ] Create DEX Registry - [ ] Implement DEX Detector - [ ] Build protocol interface (DEXDecoder) - [ ] Test with existing UniswapV3 ### Phase 1.2: SushiSwap Integration (Days 3-4) - [ ] Implement SushiSwapDecoder - [ ] Add SushiSwap to registry - [ ] Test cross-DEX price comparison - [ ] Deploy and validate ### Phase 1.3: Curve Integration (Days 5-6) - [ ] Implement CurveDecoder (StableSwap math) - [ ] Add Curve to registry - [ ] Test stable pair arbitrage - [ ] Deploy and validate ### Phase 1.4: Balancer Integration (Day 7) - [ ] Implement BalancerDecoder (weighted pools) - [ ] Add Balancer to registry - [ ] Full integration testing ### Phase 2: Multi-Hop (Week 2) - [ ] Implement path-finding algorithm - [ ] Build token graph from pool data - [ ] Test 3-4 hop arbitrage detection - [ ] Optimize for gas costs --- ## 🎯 Success Metrics ### Week 1 - βœ… 3+ DEXs integrated - βœ… Cross-DEX price monitoring working - βœ… 10+ profitable opportunities/day detected - βœ… $50+ daily profit ### Week 2 - βœ… 5+ DEXs integrated - βœ… Multi-hop paths working (3-4 hops) - βœ… 50+ profitable opportunities/day - βœ… $200+ daily profit --- *Created: October 26, 2025* *Status: DESIGN COMPLETE - READY FOR IMPLEMENTATION* *Priority: CRITICAL - Required for profitability*