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:
- Analytics — study your protocol, smart contracts, typical user transactions, current level of MEV activity.
- Design — select a combination of protection methods according to your requirements (security, UX, budget).
- Implementation — write smart contracts (Solidity), integrate private RPCs, configure dynamic slippage.
- Testing — cover with unit tests and fuzzing (Echidna), run on testnet, simulate sandwich attacks.
- 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.







