Protection System Against Sandwich Attacks in DeFi

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1All 1305 services
Protection System Against Sandwich Attacks in DeFi
Medium
from 1 day to 3 days
Frequently Asked Questions

Blockchain Development Services

Blockchain Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1349
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    949
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1183
  • image_logo-advance_0.webp
    B2B Advance company logo design
    642
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    921

Protection System Against Sandwich Attacks in DeFi

The average loss from a sandwich attack is $100–200 per transaction, and for large swaps it can reach $10,000. Implementing protection can save up to $20,000 per month in MEV losses. Our team has 5 years of blockchain development experience and has delivered over 50 projects for DeFi protocol protection. Contact us for a free assessment of your project.

A sandwich attack is a form of MEV where an attacker places transactions before and after a user's swap in the public mempool. On Uniswap-like AMMs, this results in up to 5% loss of the swap amount for ordinary users. We help projects eliminate this vulnerability at the smart contract and infrastructure level. If your project suffers from MEV, get an expert consultation today.

How Does a Sandwich Attack Work and Why Is It a Problem?

To understand protection, let's break down the attack mechanism. The public mempool allows MEV bots to see all pending transactions. The bot analyzes swap parameters (token address, amount, slippage tolerance) and calculates how much to buy before the victim and sell after to profit. The higher the allowed slippage, the wider the attack window. According to EigenPhi, large sandwich bots on Ethereum earned hundreds of thousands of dollars per week at the expense of regular users. According to Wikipedia (link), sandwich attacks account for up to 30% of all MEV transactions. A 2023 study found that sandwich attacks cost users $1.3 billion in MEV.

The vulnerability lies in the deterministic price impact: for an AMM with the formula x*y=k, the attacker can precisely calculate the front-run swap volume that yields maximum profit. Weak spots are high slippage and the public nature of the mempool.

What Protection Methods Do We Apply?

We use three layers of protection: at the transaction level, at the smart contract level, and at the protocol architecture level. Below we compare the main approaches:

Method Effectiveness Implementation Complexity UX
Private RPC (Flashbots Protect) Reduces risk by 95% Low (1–2 weeks) No changes
Commit-reveal contract Blocks 99% of attacks Medium (2–3 weeks) Two steps (heavy UX)
Batch auction (CoW Protocol) Completely eliminates High (2–4 months) No changes
Dynamic slippage Reduces by 50–70% Medium (2–3 weeks) Automatic

For example, commit-reveal is two times more effective than dynamic slippage against targeted attacks with high slippage.

Private RPC and MEV Protection Providers

The fastest protection is to send transactions not to the public mempool but directly to block builders. Flashbots Protect routes transactions into Flashbots bundles—the attacker cannot see them. MEV Blocker by CoW Protocol competitively executes the swap through multiple searchers and returns part of the MEV to the user. Bloxroute offers protected channels for a fee. Below is a comparison of providers:

Provider Type Cost Additional Features
Flashbots Protect Private relay Free (gas) Bundle support, ethers.js compatibility
MEV Blocker (CoW) Searcher auction 0% fee Returns MEV to user
Bloxroute Protected channel Paid Low latency, private stream
// Using Flashbots Protect via ethers.js
const { FlashbotsBundleProvider } = require('@flashbots/ethers-provider-bundle');
const { ethers } = require('ethers');

async function protectedSwap(swapParams, wallet, provider) {
    // Connect to Flashbots relay
    const flashbotsProvider = await FlashbotsBundleProvider.create(
        provider,
        wallet,
        'https://relay.flashbots.net'
    );
    
    // Build swap transaction as usual
    const swapTx = await buildSwapTransaction(swapParams);
    
    // Send via Flashbots
    const bundleSubmission = await flashbotsProvider.sendPrivateTransaction(
        {
            signer: wallet,
            transaction: swapTx
        },
        { maxBlockNumber: (await provider.getBlockNumber()) + 10 }
    );
    
    const receipt = await bundleSubmission.wait();
    return receipt;
}
Example implementation of a commit-reveal contract
contract CommitRevealSwap {
    mapping(bytes32 => Commitment) public commitments;
    
    struct Commitment {
        address user;
        uint256 blockNumber;
        bool revealed;
    }
    
    uint256 public constant MIN_BLOCKS_BEFORE_REVEAL = 1;
    uint256 public constant MAX_BLOCKS_BEFORE_REVEAL = 10;
    
    function commit(bytes32 commitHash) external {
        commitments[commitHash] = Commitment({
            user: msg.sender,
            blockNumber: block.number,
            revealed: false
        });
    }
    
    function reveal(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        bytes32 salt
    ) external {
        bytes32 commitHash = keccak256(abi.encodePacked(
            msg.sender, amountIn, amountOutMin, 
            keccak256(abi.encode(path)), salt
        ));
        
        Commitment storage commitment = commitments[commitHash];
        require(commitment.user == msg.sender, "Not your commit");
        require(!commitment.revealed, "Already revealed");
        require(
            block.number >= commitment.blockNumber + MIN_BLOCKS_BEFORE_REVEAL,
            "Too early"
        );
        require(
            block.number <= commitment.blockNumber + MAX_BLOCKS_BEFORE_REVEAL,
            "Expired"
        );
        
        commitment.revealed = true;
        _executeSwap(amountIn, amountOutMin, path, msg.sender);
    }
}

Batch Auctions: CoW Protocol's Architectural Solution

CoW Protocol solves the problem at the architecture level. Orders are collected over a period (several blocks), an off-chain solver finds the optimal execution for the entire batch, and a single settlement transaction is published with a uniform price. In a batch auction, there is no room for a sandwich: the attacker cannot insert between order and execution because they are separated in time.

Standard AMM:
Block N:   frontrun_buy → user_swap → backrun_sell

CoW Batch Auction:
Block N:   submit_order(user1), submit_order(user2), ...
Block N+3: solver publishes settlement_tx with uniform price

How We Design the Protection System

The process consists of five stages:

  1. Analytics — study your protocol, smart contracts, typical user transactions, current level of MEV activity.
  2. Design — select a combination of protection methods according to your requirements (security, UX, budget).
  3. Implementation — write smart contracts (Solidity), integrate private RPCs, configure dynamic slippage.
  4. Testing — cover with unit tests and fuzzing (Echidna), run on testnet, simulate sandwich attacks.
  5. Deployment and monitoring — deploy on mainnet, connect MEV activity monitoring (Tenderly, custom dashboards).

We guarantee transparency: each stage is accompanied by documentation, we provide access to the repository and training for your team.

What's Included

  • Audit of current architecture and identification of vulnerabilities to sandwich attacks.
  • Development and implementation of selected protection methods.
  • Source code of smart contracts (Solidity) with test coverage.
  • Configuration of private RPCs (Flashbots, MEV Blocker) — setup and integration.
  • Operational documentation and user instructions.
  • Monitoring system with alerts for spikes in MEV activity.
  • Technical support for 3 months after deployment.

Timeline and Cost

Timelines depend on complexity: private RPC integration — from 1 week; commit-reveal contract — from 2 weeks; full system with monitoring — from 4 weeks; batch auction protocol — from 2 months. Cost is calculated individually for your project — contact us, and we will evaluate the task within 2 business days.

Monitoring and Attack Detection

For continuous protection, we implement a monitoring component that tracks MEV bot activity, analyzes user losses, and sends alerts during anomalous sandwich spikes. Implementing such a system can save up to $15,000 per month.

async function detectSandwichInBlock(blockNumber, provider, uniswapAddress) {
    const block = await provider.getBlock(blockNumber, true);
    const uniswapTxs = block.transactions.filter(
        tx => tx.to?.toLowerCase() === uniswapAddress.toLowerCase()
    );
    
    const sandwiches = [];
    
    for (let i = 1; i < uniswapTxs.length - 1; i++) {
        const prev = uniswapTxs[i - 1];
        const current = uniswapTxs[i];
        const next = uniswapTxs[i + 1];
        
        if (prev.from === next.from && prev.from !== current.from) {
            const prevDecoded = decodeSwap(prev.data);
            const nextDecoded = decodeSwap(next.data);
            
            if (prevDecoded && nextDecoded && 
                prevDecoded.tokenIn === nextDecoded.tokenOut) {
                sandwiches.push({
                    attacker: prev.from,
                    victim: current.from,
                    frontrunTx: prev.hash,
                    victimTx: current.hash,
                    backrunTx: next.hash,
                    estimatedProfit: calculateSandwichProfit(prevDecoded, nextDecoded)
                });
            }
        }
    }
    
    return sandwiches;
}

Get an expert consultation on DeFi protection today. Contact us for a free assessment of your project.

How Do We Find What the Compiler Misses?

When a protocol loses $197M through a flash loan attack on a function that auditors reviewed live — it's not an accident. It's a systemic gap in methodology. Our experience shows: vulnerabilities live in a contract for over a year, while the compiler remains silent. We restructured the audit process to catch such cases before deployment.

What Static Analysis Won't Find?

Slither is the standard first tool. It finds reentrancy, integer overflow (in older Solidity versions), improper use of tx.origin, variable shadowing, uninitialized storage. On a real project, Slither produces dozens of warnings, of which critical ones are 0‑2. The rest is informational noise.

Slither won't find logical vulnerabilities. If withdraw correctly checks balance and correctly updates state, but business logic allows double deduction through two different code paths — Slither stays silent.

Mythril uses symbolic execution: builds a graph of all possible execution paths and searches for reachable states violating properties. Works well on isolated contracts. On a protocol of 20 contracts with cross‑contract calls — path explosion, analysis hangs or returns false positives.

Both tools are mandatory as a first pass. But they don't replace manual analysis.

Fuzzing: Where Echidna and Foundry Find Real Bugs

Echidna is a property‑based fuzzer from Trail of Bits. The idea: formulate contract invariants as Solidity functions (echidna_invariant), Echidna generates random call sequences and tries to break the invariant.

Example invariant for a lending protocol:

function echidna_total_assets_ge_liabilities() public view returns (bool) {
    return totalAssets() >= totalLiabilities();
}

Echidna will find a sequence deposit → borrow → liquidate → repay that violates this invariant. You can't build such a case manually — too many combinations.

Foundry fuzzing (forge test --fuzz-runs 100000) is easier to integrate if the team is already on Foundry. Supports stateful fuzzing via invariant tests. In a real project: auditing a vault contract, Foundry fuzzed for 40 minutes and found an edge case where maxWithdraw returned a value larger than actual balance at a specific shares/assets ratio after several donations. Hardhat unit tests missed it — they didn't have that combination of parameters.

Medusa (from Trail of Bits, newer than Echidna) supports corpus‑guided fuzzing and runs faster on large contracts. If the codebase exceeds 5000 lines of Solidity — we look at Medusa.

How Invariants Help Identify Critical Vulnerabilities

Formal verification proves that the contract satisfies specifications for all possible inputs — not for N random ones, but mathematically for all. Tools: Certora Prover, K Framework, Halmos.

Certora works with CVL (Certora Verification Language): write rules and invariants, the Prover translates them into SMT formulas and checks via Z3/CVC5. MakerDAO, Aave, Uniswap use Certora in CI/CD pipeline — every PR is automatically verified.

Limitations: doesn't work with unbounded loops, struggles with hash functions and signature verification. For contracts with simple math (AMM, lending) — excellent. For contracts with arbitrary external calls — difficult to write sufficiently complete specifications.

Formal verification makes sense for contracts that: manage over $50M, are rarely updated, have clearly formalizable invariants. For fast‑iterating products — the cost‑benefit ratio doesn't favor verification.

What Attack Vectors Do Junior Auditors Miss?

Storage collision in proxy pattern. Transparent proxy and UUPS use specific slots for implementation address (EIP‑1967). If an implementation accidentally declares a variable in slot 0 that overlaps with proxy storage — we get silent override. Slither won't catch this if proxy and implementation are in different files.

Read‑only reentrancy. Classic reentrancy guard protects against state changes during recursive calls. But if an external contract reads state via a view function mid‑transaction — guard doesn't help. Years ago, Curve pools became an attack vector precisely through this: an external protocol read get_virtual_price during a reentrancy‑vulnerable state of Curve.

Oracle manipulation via TWAP. Spot price is a standard target for flash loan attack. TWAP is harder to manipulate, but not impossible: on low‑liquidity Uniswap v2 pairs, TWAP can be shifted over several blocks with enough capital. Proper protection: use Chainlink as primary oracle with TWAP as fallback, with deviation threshold check.

Gas griefing on unbounded loop. A function iterates over an array of users. Attacker adds thousands of addresses with zero balances — the function's gas cost rises to the gas limit, making it inaccessible. Protection: pull pattern instead of push, limit array lengths, batch processing with position tracking.

Front‑running on MEV. Transaction is visible in mempool before inclusion in block. MEV bot sees addLiquidity for a significant amount, inserts its own swap before it (sandwich attack). For AMM this is part of the model. For protocols with price functions — require minAmountOut / deadline parameter and its mandatory verification.

Structure of a Full Audit

  1. Scope definition and automated analysis (1‑2 days). Fix commit hash, compiler version, list of out‑of‑scope items. Run Slither, Mythril, Aderyn. Triage: separate real critical bugs from false positives. Build contract dependency map.

  2. Manual analysis (5‑15 days). Each contract line by line. Special attention: all external and public functions, all transfer/call/delegatecall, all places where state changes before a check or after an external call, all math operations with user inputs. On average, 95% of found vulnerabilities are logical, not technical.

  3. Fuzzing and testing (2‑5 days). Echidna or Foundry invariant tests for critical invariants. Fork mainnet tests — verify behavior in real environment with real oracles. For example, in 4 days fuzzing finds on average 3 edge cases not covered by unit tests.

  4. Report and mitigation. Report with severity (Critical/High/Medium/Low/Informational), attack vector description, PoC code for Critical/High. Developers fix, auditors perform re‑audit of fixes.

Severity Examples Requires re‑audit?
Critical Drain funds, unauthorized ownership transfer Always
High Manipulation, DoS on key functions Always
Medium Incorrect behavior on edge cases Recommended
Low Gas inefficiency, typos in events Optional

Audit in CI/CD

Common practice for mature protocols: Slither and Aderyn run in GitHub Actions on every PR. Certora Prover — on merge to main. This doesn't replace a full audit before deployment, but catches regressions.

# .github/workflows/audit.yml
- name: Run Slither
  uses: crytic/[email protected]
  with:
    target: 'src/'
    slither-args: '--filter-paths "test|mock|script"'
Checklist of mandatory checks before deployment
  • All external functions have access controls (onlyOwner, onlyRole)
  • Use SafeERC20 for external tokens
  • No delegatecall to unknown addresses
  • Reentrancy check in all functions with external calls
  • Presence of minAmountOut and deadline in AMM functions
  • Use of a trusted oracle (Chainlink) with deviation threshold

Audit Tools Comparison

Tool Type of Analysis What It Finds Limitations
Slither Static Reentrancy, integer overflow, access control Misses logical vulnerabilities
Mythril Symbolic execution Reachable states violating properties Path explosion on large codebases
Echidna Fuzzing (property‑based) Invariant violations Requires writing invariants
Certora Formal verification Mathematical proof of properties Doesn't work with hashes/signatures

Deliverables

  • Full report in PDF with CVSS scores for each vulnerability
  • PoC code for all Critical and High (reproducible in test environment)
  • Remediation recommendations with code examples
  • Re‑audit after fixes (up to two iterations)
  • Brief guide for developers on ongoing operation
  • Post‑deployment support for 30 days (consultations and incident analysis)

Timeline

Audit of a simple token or NFT contract — 3‑5 business days. DeFi protocol with lending/AMM — 2‑4 weeks. Full stack with multiple protocols, cross‑chain, proxy upgrades — 4‑8 weeks. Re‑audit of fixes — 3‑7 days separately.

Our team has 7+ years of experience in smart contract security, having audited over 100 projects. We guarantee we won't miss any known attack vectors — we use licensed versions of Slither and best fuzzer configurations. Assess your project — we will analyze your code for free and provide a commercial offer within 2 days. Order an audit with quality guarantee and get a discount on re‑audit for repeat customers.