Minimax Algorithm
How the minimax search algorithm from game theory applies to cross-chain routing — and why it produces better outcomes than expected-value optimization.
The Chess Connection
In chess, the minimax algorithm evaluates every possible move by assuming the opponent plays optimally. It picks the move that maximizes your minimum guaranteed score — the best you can do even when the opponent plays perfectly.
Cross-chain routing is the same problem in a different domain. The "opponent" is not a person — it's the combined adversarial force of market conditions, MEV bots, bridge congestion, and gas spikes. These forces don't coordinate, but they all work against the user's outcome. Minimax treats them as a single adversary that plays optimally against each route.
| Chess | MNMX Routing |
|---|---|
| Board positions | Candidate routes |
| Possible moves | Possible paths (bridge + DEX combinations) |
| Opponent's best response | Worst-case market conditions |
| Position evaluation | Route scoring (fees + slippage + risk) |
| Minimax score | Guaranteed minimum output |
| Alpha-beta pruning | Early elimination of dominated routes |
| Evaluation depth | Number of adversarial factors modeled |
| Time control | Quote timeout budget |
Formal Definition
The minimax value of a route R is defined as:
1minimax(R) = max_R [ min_A [ score(R, A) ] ]2
3Where:4 R = set of candidate routes5 A = set of adversarial conditions6 score(R, A) = net output of route R under adversarial conditions A7
8The optimal route R* satisfies:9 R* = argmax_R [ min_A [ score(R, A) ] ]10
11In plain English:12 "Pick the route whose worst case is better than every other route's worst case."The Algorithm
MNMX applies a modified minimax with two levels:
1Level 0 (Maximizer — your routes):2 For each candidate route, compute the worst-case output.3 Pick the route with the HIGHEST worst-case output.4
5Level 1 (Minimizer — adversarial conditions):6 For each route, model all adversarial factors:7 - Slippage spike (2x quoted)8 - Gas price surge (1.5x current)9 - Bridge delay (3x median)10 - MEV extraction (0.3% of value)11 - Price movement (0.5% adverse)12 Apply all simultaneously → worst-case output for this route.1function minimax(routes: Route[]): Route {2 let bestRoute: Route | null = null;3 let bestMinimaxScore = -Infinity;4 let alpha = -Infinity; // Alpha-beta pruning bound5
6 for (const route of routes) {7 // Minimizer: compute worst-case output for this route8 const worstCase = evaluateWorstCase(route);9
10 // Alpha-beta pruning: skip if this route can't beat current best11 if (worstCase.lowerBound < alpha) {12 continue; // Prune — this route's best possible worst-case is below alpha13 }14
15 // Maximizer: pick route with best worst-case16 if (worstCase.score > bestMinimaxScore) {17 bestMinimaxScore = worstCase.score;18 bestRoute = route;19 alpha = bestMinimaxScore; // Raise pruning threshold20 }21 }22
23 return bestRoute;24}25
26function evaluateWorstCase(route: Route): Evaluation {27 let output = route.quotedOutput;28
29 // Apply all adversarial conditions simultaneously30 output -= route.slippage * 2.0; // 2x slippage31 output -= route.gasCost * 1.5; // 1.5x gas32 output -= route.value * 0.003; // MEV extraction33 output -= route.value * 0.005; // Adverse price movement34 output -= route.bridgeRiskPenalty; // Bridge-specific risk35
36 // Compute lower bound for early pruning37 // (assumes best possible outcome for remaining adversarial factors)38 const lowerBound = output;39
40 return { score: output, lowerBound, route };41}Worked Example With Real Numbers
Let's trace through a complete minimax evaluation for a real transfer: 10 ETH on Ethereum to SOL on Solana. Current market price: 1 ETH = 14.3 SOL.
1Input: 10 ETH ($32,500 at $3,250/ETH)2Target: SOL on Solana ($225/SOL)3Ideal output (zero-fee): 144.44 SOL4
5═══════════════════════════════════════════════════════════════════6ROUTE A: Wormhole Direct7 ETH(Ethereum) → Wormhole → ETH(Solana) → Jupiter(ETH→SOL)8═══════════════════════════════════════════════════════════════════9
10Quoted output breakdown:11 Bridge fee: 0.04 ETH ($130) → 143.87 SOL equivalent12 Jupiter swap: 0.18% price impact → -0.259 SOL13 Ethereum gas: $12.50 (21,000 gas @ 45 gwei)14 Solana gas: $0.02 (5,000 compute units)15 ─────────────────────────────────────────────16 Quoted output: 143.55 SOL17
18Worst-case modeling:19 Slippage (2x): -0.259 SOL additional → 143.29 SOL20 Gas surge (1.5x): -$6.26 (additional gas) → 143.26 SOL21 MEV (0.3%): -0.430 SOL → 142.83 SOL22 Price move (0.5%): -0.714 SOL → 142.12 SOL23 Bridge risk: -0.143 SOL (99.2% success rate) → 141.98 SOL24 ─────────────────────────────────────────────25 MINIMAX SCORE: 141.98 SOL26
27═══════════════════════════════════════════════════════════════════28ROUTE B: deBridge DLN Direct29 ETH(Ethereum) → deBridge DLN → ETH(Solana) → Jupiter(ETH→SOL)30═══════════════════════════════════════════════════════════════════31
32Quoted output breakdown:33 Bridge fee: 0.02 ETH ($65) → 144.15 SOL equivalent34 Jupiter swap: 0.18% price impact → -0.259 SOL35 Ethereum gas: $14.00 (complex calldata)36 Solana gas: $0.0237 ─────────────────────────────────────────────38 Quoted output: 143.83 SOL39
40Worst-case modeling:41 Slippage (2x): -0.259 SOL → 143.57 SOL42 Gas surge (1.5x): -$7.00 → 143.54 SOL43 MEV (0.3%): -0.431 SOL → 143.11 SOL44 Price move (0.5%): -0.716 SOL → 142.39 SOL45 Bridge risk: -0.072 SOL (99.6% success) → 142.32 SOL46 ─────────────────────────────────────────────47 MINIMAX SCORE: 142.32 SOL48
49═══════════════════════════════════════════════════════════════════50ROUTE C: Stablecoin Multi-Hop51 ETH(Ethereum) → Uniswap(ETH→USDC) → deBridge(USDC) →52 Jupiter(USDC→SOL) on Solana53═══════════════════════════════════════════════════════════════════54
55Quoted output breakdown:56 Uniswap swap: 0.05% price impact on ETH/USDC → 32,483.75 USDC57 Bridge fee: $3.50 (USDC bridges cheaply) → 32,480.25 USDC58 Jupiter swap: 0.08% price impact on USDC/SOL → 144.24 SOL59 Ethereum gas: $15.00 (swap + bridge initiate)60 Solana gas: $0.0261 ─────────────────────────────────────────────62 Quoted output: 144.17 SOL63
64Worst-case modeling:65 Slippage (2x): -0.094 SOL (low impact pairs) → 144.08 SOL66 Gas surge (1.5x): -$7.51 → 144.04 SOL67 MEV (0.3%): -0.432 SOL → 143.61 SOL68 Price move (0.5%): -0.720 SOL → 142.89 SOL69 Bridge risk: -0.072 SOL (deBridge, 99.6%) → 142.82 SOL70 ─────────────────────────────────────────────71 MINIMAX SCORE: 142.82 SOL ← HIGHEST72
73═══════════════════════════════════════════════════════════════════74ROUTE D: Multi-Hop via Arbitrum75 ETH(Ethereum) → LayerZero(ETH→Arbitrum) → Uniswap(ETH→USDC) →76 Wormhole(USDC→Solana) → Jupiter(USDC→SOL)77═══════════════════════════════════════════════════════════════════78
79Quoted output breakdown:80 LayerZero bridge: 0.01 ETH ($32.50)81 Arbitrum Uniswap: 0.04% price impact82 Wormhole bridge: $2.00 (USDC)83 Jupiter swap: 0.08% price impact84 Ethereum gas: $12.0085 Arbitrum gas: $0.3586 Solana gas: $0.0287 ─────────────────────────────────────────────88 Quoted output: 143.92 SOL89
90Worst-case modeling:91 Slippage (2x): -0.086 SOL → 143.83 SOL92 Gas surge (1.5x): -$6.19 (3 chains!) → 143.80 SOL93 MEV (0.3%): -0.431 SOL → 143.37 SOL94 Price move (0.5%): -1.434 SOL (TWO bridges!) → 141.94 SOL95 Bridge risk: -0.288 SOL (2 bridges compound) → 141.65 SOL96 ─────────────────────────────────────────────97 MINIMAX SCORE: 141.65 SOL98
99═══════════════════════════════════════════════════════════════════100RESULT: Route C wins with minimax score 142.82 SOL101═══════════════════════════════════════════════════════════════════102
103Ranking by minimax score:104 1. Route C (stablecoin multi-hop): 142.82 SOL ← SELECTED105 2. Route B (deBridge direct): 142.32 SOL106 3. Route A (Wormhole direct): 141.98 SOL107 4. Route D (multi-hop via Arbitrum): 141.65 SOL108
109Note: Route D had the highest QUOTED output (143.92) but the110LOWEST minimax score (141.65) due to compounding risk from111two bridge hops. This is exactly the kind of trap that expected-112value optimization falls into.Minimax vs Expected Value
Most routers use expected value optimization — they estimate the most likely outcome for each route and pick the highest. Here's why minimax is better for cross-chain:
The Probability Problem
Expected value requires knowing the probability of each outcome. In cross-chain, these probabilities are fundamentally unknowable:
- Bridge delays are driven by validator set behavior, network congestion, and consensus mechanics that vary unpredictably
- MEV extraction depends on the current mempool state and the sophistication of searchers watching your transaction
- Liquidity depth can change in the milliseconds between quote and execution as other users trade
- Gas prices spike non-linearly during high-demand events (token launches, liquidation cascades)
Expected value routers must assign probabilities to these events. If those probabilities are wrong (and they always are), the "optimal" route is suboptimal. Minimax sidesteps this entirely by not using probabilities at all.
Concrete Example
1Transfer: 1 ETH → SOL2
3Route A (Wormhole direct):4 Best case: 14.5 SOL (probability: 60%)5 Worst case: 11.2 SOL (probability: 40%)6 Expected value: 14.5 x 0.6 + 11.2 x 0.4 = 13.18 SOL7 Minimax score: 11.2 SOL8
9Route B (Multi-hop via Arbitrum):10 Best case: 14.2 SOL (probability: 70%)11 Worst case: 13.8 SOL (probability: 30%)12 Expected value: 14.2 x 0.7 + 13.8 x 0.3 = 14.08 SOL13 Minimax score: 13.8 SOL14
15Expected value picks: Route B (14.08 > 13.18) ← correct here16Minimax picks: Route B (13.8 > 11.2) ← also correct, same answer17
18But what if probabilities are wrong?1What if actual worst-case probability was 70%, not 40%?2
3Route A actual: 14.5 x 0.3 + 11.2 x 0.7 = 12.19 SOL ← much worse4Route B actual: 14.2 x 0.3 + 13.8 x 0.7 = 13.92 SOL ← barely changed5
6Minimax doesn't need to know probabilities.7It just guarantees Route B gives you AT LEAST 13.8 SOL.8Period.In cross-chain, probability estimates are unreliable — bridge delays are unpredictable, MEV is adversarial, liquidity conditions change between quote and execution. Minimax doesn't need probability estimates. It gives you the best guaranteed floor.
Why Variance Matters More Than Mean
Consider a user bridging $50,000 USDC from Ethereum to Solana. Two routes are available:
1Route X: Expected output $49,850 | Worst case: $49,200 | Variance: $6502Route Y: Expected output $49,900 | Worst case: $48,500 | Variance: $1,4003
4Expected value picks Route Y (saves $50 on average).5But Route Y can cost $700 MORE in the worst case.6
7For a $50,000 transfer, the user cares far more about avoiding8a $1,500 loss than capturing an extra $50 on average.9
10Minimax picks Route X: guaranteed to lose at most $800.11Route Y could lose up to $1,500.12
13The rational choice is Route X unless you're making thousands14of identical transfers and can afford to average out.Alpha-Beta Pruning
When evaluating many candidate paths, alpha-beta pruning eliminates routes that cannot possibly beat the current best. This is the same optimization used in chess engines to search deeper within the same time budget.
1Routes to evaluate: [A, B, C, D, E, F, G, H, I, J, K, L]2Alpha (best minimax found so far): -Infinity3
4Evaluate A:5 Quoted output: 143.55 SOL6 Apply adversarial conditions...7 Minimax score: 141.98 SOL8 Alpha = 141.989
10Evaluate B:11 Quoted output: 143.83 SOL12 Apply adversarial conditions...13 Minimax score: 142.32 SOL14 Alpha = 142.32 (new best)15
16Evaluate C:17 Quoted output: 144.17 SOL18 Apply adversarial conditions...19 Minimax score: 142.82 SOL20 Alpha = 142.82 (new best)21
22Evaluate D:23 Quoted output: 143.92 SOL24 After slippage + gas penalties: 143.80 SOL25 After MEV penalty: 143.37 SOL26 After price movement: 141.94 SOL ← already below alpha (142.82)!27 PRUNE — no need to compute bridge risk. This route cannot beat C.28
29Evaluate E:30 Quoted output: 142.10 SOL ← below alpha before ANY penalties31 PRUNE immediately — quoted output is already below best minimax.32
33Evaluate F:34 Quoted output: 143.50 SOL35 After first penalty: 143.20 SOL36 After second penalty: 142.65 SOL ← below alpha37 PRUNE — cannot beat C.38
39...continue...40
41Result: Only 5 of 12 routes fully evaluated. Same result, 58% less work.The efficiency of alpha-beta pruning depends on the order in which routes are evaluated. MNMX sorts routes by estimated quality before evaluation, which means the best route is likely evaluated early, setting a high alpha threshold that prunes more aggressively. In practice, this reduces the number of full evaluations by 40-60%.
Pruning Implementation
1class MinimaxEvaluator {2 evaluate(routes: Route[], config: AdversarialConfig): Route {3 // Pre-sort by estimated quality (heuristic: lower fees + higher liquidity)4 const sorted = routes.sort((a, b) =>5 this.estimateQuality(b) - this.estimateQuality(a)6 );7
8 let bestRoute: Route | null = null;9 let alpha = -Infinity;10 let evaluationCount = 0;11 let pruneCount = 0;12
13 for (const route of sorted) {14 // Quick check: can this route's quoted output even beat alpha?15 if (route.quotedOutput < alpha) {16 pruneCount++;17 continue; // Quoted output already below best worst-case18 }19
20 // Incremental evaluation with early termination21 const result = this.evaluateWithPruning(route, config, alpha);22 evaluationCount++;23
24 if (result.pruned) {25 pruneCount++;26 continue;27 }28
29 if (result.score > alpha) {30 alpha = result.score;31 bestRoute = route;32 }33 }34
35 console.log(36 `Evaluated ${evaluationCount}/${routes.length} routes, pruned ${pruneCount}`37 );38
39 return bestRoute!;40 }41
42 private evaluateWithPruning(43 route: Route,44 config: AdversarialConfig,45 alpha: number46 ): { score: number; pruned: boolean } {47 let output = route.quotedOutput;48
49 // Apply penalties one at a time, checking alpha after each50 const penalties = [51 () => route.slippage * config.slippageMultiplier,52 () => route.gasCost * config.gasMultiplier - route.gasCost,53 () => route.value * config.mevExtraction,54 () => route.value * config.priceMovement * route.bridgeCount,55 () => this.calculateBridgeRisk(route),56 ];57
58 for (const penalty of penalties) {59 output -= penalty();60 if (output < alpha) {61 return { score: output, pruned: true };62 }63 }64
65 return { score: output, pruned: false };66 }67}Route Scoring Function
Each route is scored across five dimensions. The combined score represents the net output in destination tokens:
| Dimension | Weight | Calculation | Description |
|---|---|---|---|
| Total fees | 0.25 | gas_usd + bridge_fees_usd + swap_fees_usd | Sum of gas, bridge, and swap fees across all hops |
| Slippage impact | 0.25 | Sum of price_impact per pool * amount | Price impact from swaps and low bridge liquidity |
| Transfer speed | 0.15 | Sum of p90_confirmation_time per hop | Expected total time from start to completion |
| Bridge reliability | 0.20 | Product of success_rates * tvl_score * audit_score | Historical uptime, TVL, security audit score |
| MEV exposure | 0.15 | unprotected_swap_value * historical_extraction_rate | Risk of value extraction during multi-hop execution |
The weighted score is normalized to a 0-1 scale where higher is better:
1function computeWeightedScore(2 route: Route,3 state: PathState,4 weights: ScoringWeights5): number {6 // Normalize each dimension to 0-1 scale7 const feeScore = 1 - (state.totalFeesUSD / state.transferValueUSD);8 const slippageScore = 1 - state.totalSlippage;9 const speedScore = Math.max(0, 1 - (state.totalTime / 1200)); // 20 min max10 const reliabilityScore = state.bridgeHealth.reduce(11 (acc, h) => acc * h.recentSuccessRate, 1.012 );13 const mevScore = 1 - state.mevExposure;14
15 return (16 weights.fees * feeScore +17 weights.slippage * slippageScore +18 weights.speed * speedScore +19 weights.reliability * reliabilityScore +20 weights.mevExposure * mevScore21 );22}Adversarial Factor Calibration
The adversarial multipliers are not arbitrary — they are calibrated from historical execution data. The table below shows how each factor was derived:
| Factor | Default | Derivation | Last Calibration |
|---|---|---|---|
| Slippage multiplier | 2.0x | p99 of actual/quoted slippage ratio across 50K+ swaps | Rolling 30-day window |
| Gas multiplier | 1.5x | p95 of gas price ratio (execution vs quote time) across 100K+ txs | Rolling 7-day window |
| Bridge delay | 3.0x | p95 of actual/median confirmation time per bridge | Rolling 7-day window |
| MEV extraction | 0.3% | Mean extracted value on unprotected swaps >$1K, measured via sandwich detection | Rolling 30-day window |
| Price movement | 0.5% | p95 adverse price change of major pairs over median bridge confirmation time | Rolling 7-day window |
User Strategy Profiles
Users can adjust the scoring weights to match their priorities. Each strategy shifts the minimax evaluation toward different trade-offs:
| Profile | Fees | Slippage | Speed | Reliability | MEV |
|---|---|---|---|---|---|
| Minimax (default) | 0.25 | 0.25 | 0.15 | 0.20 | 0.15 |
| Cheapest | 0.45 | 0.30 | 0.05 | 0.10 | 0.10 |
| Fastest | 0.10 | 0.15 | 0.50 | 0.15 | 0.10 |
| Safest | 0.10 | 0.15 | 0.10 | 0.40 | 0.25 |
1// Strategy comparison for 10 ETH → SOL transfer:2
3// Minimax (default): Picks Route C (stablecoin multi-hop)4// Guaranteed minimum: 142.82 SOL5// Rationale: Best worst-case across all dimensions6
7// Cheapest: Picks Route B (deBridge direct)8// Expected fees: $79.02 (lowest)9// Trade-off: Slightly worse worst-case (142.32 SOL)10
11// Fastest: Picks Route B (deBridge DLN)12// Expected time: 90 seconds (DLN is fastest)13// Trade-off: Higher fees than stablecoin route14
15// Safest: Picks Route C (stablecoin multi-hop)16// Bridge reliability: 99.6% (deBridge) + deep USDC liquidity17// Trade-off: Slightly slower than DLN directMulti-Bridge Route Evaluation
Routes that use multiple bridges have compounding risk. The minimax evaluator handles this by multiplying bridge risk factors rather than adding them:
1Single-bridge route:2 Bridge risk = 1 - success_rate = 1 - 0.996 = 0.004 (0.4%)3
4Two-bridge route:5 Combined risk = 1 - (success_rate_A * success_rate_B)6 = 1 - (0.996 * 0.992) = 1 - 0.988 = 0.012 (1.2%)7
8 Not 0.4% + 0.8% = 1.2% (additive would be coincidentally similar here)9 But for non-independent events, the correlation matters.10
11Three-bridge route:12 Combined risk = 1 - (0.996 * 0.992 * 0.985) = 1 - 0.973 = 0.027 (2.7%)13
14This is why the minimax evaluator penalizes multi-hop routes more15heavily — each additional bridge multiplies the failure probability,16and the worst-case model amplifies this by applying the delay17multiplier to EACH bridge independently.18
19Price movement risk also compounds:20 1 bridge: 0.5% adverse movement during 1 transit21 2 bridges: 0.5% * 2 = 1.0% adverse movement during 2 transits22 3 bridges: 0.5% * 3 = 1.5% adverse movement during 3 transitsWhen Minimax Is Not Optimal
Minimax is not always the best strategy. It has known limitations that users should understand:
Conservative Bias
Conservative bias: Minimax inherently favors reliable paths over potentially more profitable but riskier ones. For users making many small transfers where individual outcomes don't matter much, the "cheapest" strategy may produce better aggregate results. Minimax is designed for users who care about the outcome of each individual transfer.
Over-Pessimism on Stable Routes
For stablecoin-to-stablecoin transfers (e.g., USDC on Ethereum to USDC on Solana), the price movement penalty is overly conservative because the price of USDC/USDC is pegged. The engine partially compensates for this by reducing the price movement multiplier for stablecoin pairs, but some conservatism remains.
State Staleness
State staleness: Route conditions can change between quote and execution. The engine re-validates conditions before executing each step and will abort if conditions degrade beyond tolerance. The worst-case model accounts for this with the adversarial multipliers, but extreme market events (flash crashes, protocol exploits) can exceed even worst-case assumptions.
Algorithm Comparison
| Property | Minimax (MNMX) | Expected Value | Greedy (lowest fee) |
|---|---|---|---|
| Requires probability estimates | No | Yes | No |
| Guarantees minimum output | Yes | No | No |
| Optimal for single transfer | Yes (risk-averse) | On average | No |
| Optimal for many transfers | Conservative | Yes (if probabilities correct) | No |
| Handles adversarial conditions | By design | Only if modeled | Ignores them |
| Computation cost | O(n) with pruning | O(n) | O(n) |
| Implementation complexity | Moderate | High (needs probability model) | Low |