# Alternative MEV Strategies - Implementation Guide **Date:** October 26, 2025 **Purpose:** Expand beyond atomic arbitrage to profitable MEV extraction --- ## 🎯 Overview Based on profitability analysis, atomic arbitrage alone is insufficient. This guide covers three high-profit MEV strategies: 1. **Sandwich Attacks** - Front-run + back-run large swaps 2. **Liquidations** - Liquidate under-collateralized lending positions 3. **JIT Liquidity** - Just-in-time liquidity provision --- ## 🥪 Strategy 1: Sandwich Attacks ### What is a Sandwich Attack? ``` User submits: Swap 100 ETH → USDC (0.5% slippage tolerance) MEV Bot sees this in mempool: 1. Front-run: Buy USDC (pushes price up) 2. User's swap executes (at worse price due to #1) 3. Back-run: Sell USDC (profit from price impact) Profit: Price impact captured = User's slippage ``` ### Profitability ``` Target: Swaps > $10,000 with slippage > 0.3% Profit per sandwich: $5-$50 (0.5-1% of swap size) Frequency: 5-20 per day on Arbitrum Daily profit: $25-$1,000 ``` ### Implementation Steps #### 1. Mempool Monitoring ```go // pkg/mev/sandwich/mempool.go package sandwich type MempoolMonitor struct { client *ethclient.Client logger *logger.Logger targetChan chan *PendingSwap } type PendingSwap struct { TxHash common.Hash From common.Address To common.Address TokenIn common.Address TokenOut common.Address AmountIn *big.Int AmountOutMin *big.Int // Minimum acceptable output Slippage float64 // Calculated from AmountOutMin GasPrice *big.Int DetectedAt time.Time } func (mm *MempoolMonitor) MonitorMempool(ctx context.Context) { pendingTxs := make(chan *types.Transaction, 1000) // Subscribe to pending transactions sub, err := mm.client.SubscribePendingTransactions(ctx, pendingTxs) if err != nil { mm.logger.Error("Failed to subscribe to mempool:", err) return } defer sub.Unsubscribe() for { select { case tx := <-pendingTxs: // Parse transaction swap := mm.parseSwapTransaction(tx) if swap != nil && mm.isSandwichable(swap) { mm.targetChan <- swap } case <-ctx.Done(): return } } } func (mm *MempoolMonitor) isSandwichable(swap *PendingSwap) bool { // Criteria for profitable sandwich: // 1. Large swap (> $10,000) // 2. High slippage tolerance (> 0.3%) // 3. Not already sandwiched minSwapSize := big.NewInt(10000e6) // $10k in USDC units minSlippage := 0.003 // 0.3% return swap.AmountIn.Cmp(minSwapSize) > 0 && swap.Slippage > minSlippage } ``` #### 2. Sandwich Calculation ```go // pkg/mev/sandwich/calculator.go type SandwichOpportunity struct { TargetTx *PendingSwap FrontRunAmount *big.Int BackRunAmount *big.Int EstimatedProfit *big.Int GasCost *big.Int NetProfit *big.Int ROI float64 } func CalculateSandwich(target *PendingSwap, pool *PoolState) (*SandwichOpportunity, error) { // 1. Calculate optimal front-run size // Too small = low profit // Too large = user tx fails (detection risk) // Optimal = ~50% of user's trade size frontRunAmount := new(big.Int).Div(target.AmountIn, big.NewInt(2)) // 2. Calculate price after front-run priceAfterFrontRun := calculatePriceImpact(pool, frontRunAmount) // 3. Calculate user's execution price (worse than expected) userOutputAmount := calculateOutput(pool, target.AmountIn, priceAfterFrontRun) // 4. Calculate back-run profit // Sell what we bought in front-run at higher price backRunProfit := calculateOutput(pool, frontRunAmount, userOutputAmount) // 5. Subtract costs gasCost := big.NewInt(300000 * 100000000) // 300k gas @ 0.1 gwei netProfit := new(big.Int).Sub(backRunProfit, frontRunAmount) netProfit.Sub(netProfit, gasCost) return &SandwichOpportunity{ TargetTx: target, FrontRunAmount: frontRunAmount, BackRunAmount: backRunProfit, EstimatedProfit: backRunProfit, GasCost: gasCost, NetProfit: netProfit, ROI: calculateROI(netProfit, frontRunAmount), }, nil } ``` #### 3. Execution (Bundle) ```go // pkg/mev/sandwich/executor.go func (se *SandwichExecutor) ExecuteSandwich( ctx context.Context, sandwich *SandwichOpportunity, ) (*ExecutionResult, error) { // Create bundle: [front-run, target tx, back-run] bundle := []common.Hash{ se.createFrontRunTx(sandwich), sandwich.TargetTx.TxHash, // Original user tx se.createBackRunTx(sandwich), } // Submit to Flashbots/MEV-Boost bundleHash, err := se.flashbots.SendBundle(ctx, bundle) if err != nil { return nil, fmt.Errorf("failed to send bundle: %w", err) } // Wait for inclusion result, err := se.waitForBundle(ctx, bundleHash) if err != nil { return nil, err } return result, nil } ``` ### Risk Mitigation **1. Detection Risk** - Use Flashbots/MEV-Boost (private mempool) - Randomize gas prices - Bundle transactions atomically **2. Failed Sandwich Risk** - User tx reverts → Our txs revert too - Mitigation: Require target tx to have high gas limit **3. Competitive Sandwiching** - Other bots target same swap - Mitigation: Optimize gas price, faster execution ### Expected Outcomes ``` Conservative Estimate: - 5 sandwiches/day @ $10 avg profit = $50/day - Monthly: $1,500 Realistic Estimate: - 10 sandwiches/day @ $20 avg profit = $200/day - Monthly: $6,000 Optimistic Estimate: - 20 sandwiches/day @ $50 avg profit = $1,000/day - Monthly: $30,000 ``` --- ## 💰 Strategy 2: Liquidations ### What are Liquidations? ``` Lending Protocol (Aave, Compound): - User deposits $100 ETH as collateral - User borrows $60 USDC (60% LTV) - ETH price drops 20% - Collateral now worth $80 - Position under-collateralized (75% LTV > 70% threshold) Liquidator: - Repays user's $60 USDC debt - Receives $66 worth of ETH (10% liquidation bonus) - Profit: $6 (10% of debt) ``` ### Profitability ``` Target: Under-collateralized positions on Aave, Compound Profit per liquidation: 5-15% of debt repaid Typical liquidation: $1,000-$50,000 debt Profit per liquidation: $50-$5,000 Frequency: 1-5 per day (volatile markets) Daily profit: $50-$500 (conservative) ``` ### Implementation Steps #### 1. Position Monitoring ```go // pkg/mev/liquidation/monitor.go type Position struct { User common.Address CollateralToken common.Address CollateralAmount *big.Int DebtToken common.Address DebtAmount *big.Int HealthFactor float64 // > 1 = healthy, < 1 = liquidatable Protocol string // "aave", "compound" LastUpdated time.Time } type LiquidationMonitor struct { aavePool *aave.Pool compTroller *compound.Comptroller priceOracle *oracle.ChainlinkOracle logger *logger.Logger } func (lm *LiquidationMonitor) MonitorPositions(ctx context.Context) { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: // 1. Fetch all open positions from Aave aavePositions := lm.getAavePositions() // 2. Fetch all open positions from Compound compoundPositions := lm.getCompoundPositions() // 3. Calculate health factors for _, pos := range append(aavePositions, compoundPositions...) { healthFactor := lm.calculateHealthFactor(pos) // Under-collateralized? if healthFactor < 1.0 { lm.logger.Info(fmt.Sprintf("🎯 Liquidation opportunity: %s", pos.User.Hex())) lm.executeLiquidation(ctx, pos) } } case <-ctx.Done(): return } } } func (lm *LiquidationMonitor) calculateHealthFactor(pos *Position) float64 { // Get current prices collateralPrice := lm.priceOracle.GetPrice(pos.CollateralToken) debtPrice := lm.priceOracle.GetPrice(pos.DebtToken) // Calculate values in USD collateralValue := new(big.Float).Mul( new(big.Float).SetInt(pos.CollateralAmount), collateralPrice, ) debtValue := new(big.Float).Mul( new(big.Float).SetInt(pos.DebtAmount), debtPrice, ) // Health Factor = (Collateral * LiquidationThreshold) / Debt liquidationThreshold := 0.70 // 70% for most assets on Aave collateralValueFloat, _ := collateralValue.Float64() debtValueFloat, _ := debtValue.Float64() return (collateralValueFloat * liquidationThreshold) / debtValueFloat } ``` #### 2. Liquidation Execution ```go // pkg/mev/liquidation/executor.go type LiquidationExecutor struct { aavePool *aave.Pool flashLoan *flashloan.Provider logger *logger.Logger } func (le *LiquidationExecutor) ExecuteLiquidation( ctx context.Context, position *Position, ) (*ExecutionResult, error) { // Strategy: Use flash loan to repay debt // 1. Flash loan debt amount // 2. Liquidate position (repay debt, receive collateral + bonus) // 3. Swap collateral to debt token // 4. Repay flash loan // 5. Keep profit // Calculate max liquidation amount (typically 50% of debt) maxLiquidation := new(big.Int).Div(position.DebtAmount, big.NewInt(2)) // Execute flash loan for liquidation userData := le.encodeLiquidationData(position, maxLiquidation) result, err := le.flashLoan.ExecuteFlashLoan( ctx, position.DebtToken, maxLiquidation, userData, ) if err != nil { return nil, fmt.Errorf("liquidation failed: %w", err) } return result, nil } ``` #### 3. Flash Loan Callback ```solidity // contracts/liquidation/LiquidationBot.sol function receiveFlashLoan( IERC20[] memory tokens, uint256[] memory amounts, uint256[] memory feeAmounts, bytes memory userData ) external override { require(msg.sender == BALANCER_VAULT, "Only vault"); // Decode liquidation data (address user, address collateralAsset, address debtAsset, uint256 debtToCover) = abi.decode(userData, (address, address, address, uint256)); // 1. Approve Aave to take debt tokens IERC20(debtAsset).approve(AAVE_POOL, debtToCover); // 2. Liquidate position IAavePool(AAVE_POOL).liquidationCall( collateralAsset, // Collateral to receive debtAsset, // Debt to repay user, // User being liquidated debtToCover, // Amount of debt to repay false // Don't receive aTokens ); // 3. Now we have collateral + liquidation bonus uint256 collateralReceived = IERC20(collateralAsset).balanceOf(address(this)); // 4. Swap collateral for debt token uint256 debtTokenReceived = swapOnUniswap( collateralAsset, debtAsset, collateralReceived ); // 5. Repay flash loan IERC20(tokens[0]).transfer(BALANCER_VAULT, amounts[0]); // 6. Profit = debtTokenReceived - debtToCover - flashLoanFee uint256 profit = debtTokenReceived - debtToCover; emit LiquidationExecuted(user, profit); } ``` ### Risk Mitigation **1. Price Oracle Risk** - Use Chainlink price feeds (most reliable) - Have backup oracle (Uniswap TWAP) - Validate prices before execution **2. Gas Competition** - Liquidations are competitive - Use high gas price or Flashbots - Monitor gas prices in real-time **3. Failed Liquidation** - Position already liquidated - Mitigation: Check health factor immediately before execution ### Expected Outcomes ``` Conservative Estimate: - 1 liquidation/day @ $100 profit = $100/day - Monthly: $3,000 Realistic Estimate (volatile market): - 3 liquidations/day @ $300 profit = $900/day - Monthly: $27,000 Optimistic Estimate (market crash): - 10 liquidations/day @ $1,000 profit = $10,000/day - Monthly: $300,000 ``` --- ## ⚡ Strategy 3: JIT Liquidity ### What is JIT Liquidity? ``` Large Swap Pending: - User wants to swap 100 ETH → USDC - Current pool has low liquidity - High price impact (1-2%) JIT Liquidity Strategy: 1. Front-run: Add liquidity to pool 2. User's swap executes (we earn LP fees) 3. Back-run: Remove liquidity 4. Profit: LP fees from large swap - gas costs ``` ### Profitability ``` Target: Large swaps with high price impact LP Fee: 0.3% (UniswapV3) or 0.05-1% (custom) Profit per JIT: $2-$50 Frequency: 10-50 per day Daily profit: $20-$2,500 ``` ### Implementation (Simplified) ```solidity // contracts/jit/JITLiquidity.sol function executeJIT( address pool, uint256 amount0, uint256 amount1, int24 tickLower, int24 tickUpper ) external { // 1. Add liquidity in tight range around current price INonfungiblePositionManager(POSITION_MANAGER).mint( INonfungiblePositionManager.MintParams({ token0: token0, token1: token1, fee: 3000, tickLower: tickLower, tickUpper: tickUpper, amount0Desired: amount0, amount1Desired: amount1, amount0Min: 0, amount1Min: 0, recipient: address(this), deadline: block.timestamp }) ); // Position will earn fees from the large swap // 2. In next block, remove liquidity // (This happens in a separate transaction after user's swap) } ``` ### Risk Mitigation **1. Impermanent Loss** - Tight price range minimizes IL - Remove liquidity immediately after swap **2. Gas Costs** - Adding/removing liquidity is expensive (400k+ gas) - Only profitable for very large swaps (>$50k) **3. Timing Risk** - User tx might not execute - Mitigation: Bundle with Flashbots ### Expected Outcomes ``` Conservative Estimate: - 5 JIT opportunities/day @ $10 profit = $50/day - Monthly: $1,500 Realistic Estimate: - 20 JIT opportunities/day @ $25 profit = $500/day - Monthly: $15,000 ``` --- ## 📊 Strategy Comparison | Strategy | Daily Profit | Complexity | Risk | Competition | |----------|-------------|------------|------|-------------| | **Sandwiches** | $200-$1,000 | Medium | Medium | High | | **Liquidations** | $100-$900 | Low | Low | Medium | | **JIT Liquidity** | $50-$500 | High | Medium | Low | | **Atomic Arbitrage** | $0-$50 | Low | Low | Very High | **Best Strategy:** Start with liquidations (low risk, consistent), then add sandwiches (high profit). --- ## 🚀 Implementation Timeline ### Week 1: Liquidations - Days 1-2: Implement position monitoring - Days 3-4: Implement liquidation executor - Days 5-6: Testing on testnet - Day 7: Small amount mainnet testing ### Week 2: Sandwiches - Days 1-2: Implement mempool monitoring - Days 3-4: Implement sandwich calculator - Days 5-6: Flashbots integration - Day 7: Testing ### Week 3: JIT Liquidity - Days 1-3: Implement JIT detection - Days 4-5: Implement JIT execution - Days 6-7: Testing --- ## 🎯 Success Criteria ### Liquidations - ✅ Monitor 100+ positions in real-time - ✅ Execute liquidation in <5 seconds - ✅ 1+ liquidation/day - ✅ $100+ profit/day ### Sandwiches - ✅ Detect 50+ viable targets/day - ✅ Execute 5+ sandwiches/day - ✅ <1% failed bundles - ✅ $200+ profit/day ### JIT Liquidity - ✅ Detect 20+ large swaps/day - ✅ Execute 5+ JIT positions/day - ✅ No impermanent loss - ✅ $50+ profit/day --- ## 📚 Resources - **Flashbots Docs:** https://docs.flashbots.net/ - **Aave Liquidations:** https://docs.aave.com/developers/guides/liquidations - **MEV Research:** https://arxiv.org/abs/1904.05234 - **UniswapV3 JIT:** https://uniswap.org/whitepaper-v3.pdf --- *Created: October 26, 2025* *Status: IMPLEMENTATION READY* *Priority: HIGH - Required for profitability*