MEV Vulnerabilities Remediation
Overview
Related Detector: MEV Vulnerabilities
MEV attacks exploit programs that perform state-dependent value transfers without protective bounds. The primary fix is to require user-supplied slippage parameters (minimum output amounts) and execution deadlines on every value-transferring operation. Combined with atomic execution patterns, these defenses make sandwich attacks unprofitable.
Recommended Fix
Before (Vulnerable)
use anchor_lang::prelude::*;
// Vulnerable: no slippage or deadline protection
pub fn execute_swap(ctx: Context<Swap>, amount: u64) -> Result<()> {
let price = get_current_price(&ctx.accounts.pool)?;
let output = calculate_output(amount, price);
transfer_tokens(&ctx, output)?;
Ok(())
}
After (Fixed)
use anchor_lang::prelude::*;
// Fixed: user-supplied minimum output and deadline
pub fn execute_swap(
ctx: Context<Swap>,
amount: u64,
min_output: u64,
deadline: i64,
) -> Result<()> {
let clock = Clock::get()?;
require!(clock.unix_timestamp <= deadline, SwapError::DeadlineExceeded);
let price = get_current_price(&ctx.accounts.pool)?;
let output = calculate_output(amount, price);
require!(output >= min_output, SwapError::SlippageExceeded);
transfer_tokens(&ctx, output)?;
Ok(())
}
Alternative Mitigations
Commit-Reveal Schemes
For operations where slippage bounds alone are insufficient, implement a two-phase commit-reveal pattern. Users commit a hashed intention in one transaction and reveal it in a later slot, preventing validators from frontrunning the actual operation.
Use a block-builder Bundles
a block-builder’s bundle mechanism allows users to submit multiple transactions atomically, reducing the window for sandwich attacks. While this is an infrastructure-level mitigation, programs should still enforce on-chain slippage bounds.
Common Mistakes
Mistake: Hardcoded Slippage Tolerance
// WRONG: hardcoded 5% slippage -- too permissive for large trades
let min_output = expected_output * 95 / 100;
Always accept the minimum output as a user-supplied parameter so traders can set appropriate bounds for their trade size.
Mistake: Missing Deadline
// WRONG: slippage check without deadline
require!(output >= min_output, SwapError::SlippageExceeded);
// Transaction could sit in mempool and execute much later at an unfavorable price
Always pair slippage checks with an expiration timestamp.