MEV Blocker Integration: Stop Frontrunning & Sandwich Attacks
Your users are losing up to 15% on sandwich attacks with every large swap. Validators copy your limit orders and execute them ahead of you. We solve this — we integrate MEV Blocker into your dApp: a private RPC endpoint that prevents MEV bots from seeing the transaction until it is confirmed.
Why Regular RPCs Don't Protect
Public RPCs (Infura, Alchemy) — all transactions are visible in the mempool. MEV bots scan the mempool and pick profitable transactions. A sandwich attack: a bot sees your swap, buys before you, waits for your price move, then sells. Result: you buy higher, sell lower. MEV Blocker is tens of times better than public RPCs in terms of confidentiality: the transaction is hidden until block inclusion.
How MEV Blocker Works
MEV Blocker is a private RPC that sends transactions directly to a private mempool (Flashbots, Eden, BloxRoute). The transaction is not published to the public mempool until it is included in a block. Block builders can see the transaction, but they cannot attack it — they receive it only at block construction time.
// Example of switching to MEV Blocker RPC in MetaMask
const provider = new ethers.providers.JsonRpcProvider('https://rpc.mevblocker.io');
// Or via EIP-1193
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x1', rpcUrls: ['https://rpc.mevblocker.io'] }],
});
What Our Work Includes
| Component | Description |
|---|---|
| RPC Setup | Deploy private MEV Blocker RPC on the dApp side |
| Wallet Integration | Automatic network switching on wallet connection |
| Transaction Monitoring | Track inclusion success and speed |
| Team Training | Provide documentation and best practices |
Why Choose Us
10+ years in blockchain development, 150+ successful DeFi protocol integrations, certified Solidity and Rust engineers. We guarantee confidentiality — we sign an NDA. We assess your project in 1 day. Contact us for a consultation — we review your architecture, identify MEV leak points, and propose an optimal integration scheme.
Additional: Source code for flash loan protection (for reference)
Protection Against Flash Loan Attacks (Ancillary Service)
A flash loan is an uncollateralized loan that must be repaid in the same transaction. If not repaid, the entire transaction is reverted. From the perspective of the lending protocol (Aave, Uniswap V3), it is a risk-free operation: either the money is returned, or the transaction never happened.
The problem is not flash loans per se — they are legitimate tools for arbitrage, liquidations, and refinancing. The problem is that they give an attacker temporary access to huge capital (hundreds of millions of dollars) without collateral. If a protocol makes economic decisions based on easily manipulable data (DEX spot price, non-TWAP oracle), a single flash loan transaction can yield millions for an attacker.
Notable exploits: Beanstalk, Cream Finance, Mango Markets. Common thread: these protocols used data that could be shifted in a single transaction.
Anatomy of a Flash Loan Attack
A typical attack consists of four steps:
- Take out a flash loan from a lending protocol
- Manipulate state (pump/dump price in a DEX pool)
- Exploit the protocol (which reads the manipulated data)
- Repay the flash loan + fee, keep the profit
Concrete example — price oracle manipulation:
1. Flash loan: a large amount of DAI
2. Dump DAI into Uniswap V2 DAI/ETH pool (spot price of DAI drops)
3. Call the protocol that reads Uniswap V2 spot price to evaluate collateral
→ Collateral in DAI now "cheaper", can get discount on liquidation
or evaluate debt in DAI as lower
4. Profit → repay flash loan
Another type — governance flash loan:
1. Flash loan governance tokens
2. Instant proposal creation + voting with enormous weight
3. Execute proposal (drain treasury)
4. Repay flash loan
(That's exactly how Beanstalk was attacked — the attacker used a single governance vote to pass a proposal transferring treasury to themselves.)
Protection 1: Price Oracle — TWAP Instead of Spot
TWAP (Time-Weighted Average Price) is the arithmetic mean price over a period. Uniswap V2/V3 stores cumulative price accumulators, from which TWAP for any period can be computed.
contract TWAPOracle {
IUniswapV3Pool public pool;
uint32 public constant TWAP_PERIOD = 30 minutes;
function getTWAP() external view returns (uint256 price) {
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = TWAP_PERIOD; // 30 minutes ago
secondsAgos[1] = 0; // now
(int56[] memory tickCumulatives,) = pool.observe(secondsAgos);
int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
int24 arithmeticMeanTick = int24(tickCumulativesDelta / int56(uint56(TWAP_PERIOD)));
// Convert tick to price
price = TickMath.getSqrtRatioAtTick(arithmeticMeanTick);
// ... convert sqrtPrice to human-readable
}
}
Choosing the TWAP period is critical. Too short (1–5 minutes) — an attacker with enough capital can keep the manipulated price for several blocks. Too long (4–8 hours) — TWAP lags behind the market in volatile periods, causing incorrect liquidations.
Practice: 30 minutes is a reasonable default for most DeFi protocols. For highly volatile assets — 1–2 hours.
Chainlink as the Primary Oracle
Chainlink price feeds aggregate prices from many independent nodes with heartbeat updates. Manipulation would require compromising most oracle nodes — economically unfeasible.
contract PriceConsumer {
AggregatorV3Interface public priceFeed;
uint256 public constant HEARTBEAT = 3600; // 1 hour
uint256 public constant MAX_STALENESS = HEARTBEAT * 2; // 2 hours maximum
function getPrice() external view returns (uint256) {
(
uint80 roundId,
int256 answer,
,
uint256 updatedAt,
uint80 answeredInRound
) = priceFeed.latestRoundData();
// Staleness check: data not older than MAX_STALENESS
require(block.timestamp - updatedAt <= MAX_STALENESS, "Stale price");
// Round correctness check
require(answeredInRound >= roundId, "Stale round");
// Positive price check
require(answer > 0, "Invalid price");
return uint256(answer);
}
}
General recommendation: use Chainlink as the primary oracle, Uniswap TWAP as a sanity check. If the two sources diverge by more than X%, pause operations.
Protection 2: Snapshot Voting Power
Governance flash loan attacks exploit the fact that voting power equals the current token balance. ERC-20Votes solves this via a checkpoint system.
// Voting power is fixed at the snapshot block (before voting starts)
uint256 votePower = token.getPastVotes(voter, proposalSnapshot);
// Flash loan AFTER snapshot yields no voting power
// Flash loan BEFORE snapshot requires holding tokens through voting delay
Voting delay — minimum period between proposal creation and voting start. With a voting delay of 2 days, an attacker must hold borrowed tokens for 2 days — economically unprofitable (fee + opportunity cost).
// OpenZeppelin Governor
constructor(...) GovernorSettings(
2 days, // votingDelay — protects against flash loan governance attacks
5 days, // votingPeriod
threshold
) {}
Beanstalk was attacked precisely because it didn't use a voting delay: a proposal could be created and executed in one transaction.
Protection 3: Reentrancy Guard and Same-Block Checks
Some flash loan attacks exploit reentrancy or same-block state manipulation.
Same-Block Checks
contract Vault {
mapping(address => uint256) private _depositBlock;
function deposit(uint256 amount) external {
_depositBlock[msg.sender] = block.number;
// ...
}
function withdraw(uint256 amount) external {
// Cannot deposit and withdraw in the same block
require(
_depositBlock[msg.sender] < block.number,
"Flash loan protection: same block"
);
// ...
}
}
This blocks the pattern: flash_loan → deposit → call function that reads vault balance → withdraw → repay_loan.
Drawback: legitimate users also cannot deposit and withdraw in the same block. For most protocols, this is acceptable.
Nonreentrant + View Functions
nonReentrant protects against reentrancy in state-changing functions. But view functions are not protected — they can be called from within another transaction.
If a view function is used by an external protocol to get price or TVL, state manipulation via reentrancy can change what that view function sees.
// VULNERABLE: state can be manipulated via reentrancy
function getSharePrice() external view returns (uint256) {
return totalAssets() * 1e18 / totalSupply();
}
// totalAssets() reads the contract's balance — which can be temporarily inflated
function totalAssets() public view returns (uint256) {
return IERC20(asset).balanceOf(address(this));
}
Solution: store a cached total assets value, updated only in protected functions.
Protection 4: Circuit Breakers and Rate Limiting
Maximum Volume Per Transaction
uint256 public constant MAX_SINGLE_DEPOSIT = 1_000_000e6; // $1M max
function deposit(uint256 amount) external {
require(amount <= MAX_SINGLE_DEPOSIT, "Exceeds single tx limit");
// ...
}
Flash loan attacks typically involve hundreds of millions. Limiting single-transaction volume reduces the maximum damage from any attack.
Pause Mechanism with Auto-Trigger
contract ProtectedProtocol is Pausable {
uint256 public lastTVL;
uint256 public constant TVL_DROP_THRESHOLD = 20; // 20% drop per transaction
modifier checkTVLAnomaly() {
uint256 tvlBefore = totalValueLocked();
_;
uint256 tvlAfter = totalValueLocked();
if (tvlBefore > 0) {
uint256 dropPercent = ((tvlBefore - tvlAfter) * 100) / tvlBefore;
if (dropPercent > TVL_DROP_THRESHOLD) {
_pause();
emit EmergencyPause(tvlBefore, tvlAfter, dropPercent);
}
}
}
}
Circuit breaker: if TVL drops more than N% in a single transaction, the protocol automatically pauses. This doesn't prevent the attack but limits its scale.
Time-Weighted Balances
Instead of current balance, use time-weighted average balance for critical calculations:
// ERC-20Votes checkpoint approach applied to liquidity
function getTimeWeightedLiquidity(address provider, uint256 lookback)
external view returns (uint256)
{
// Average liquidity over the lookback period
// A single transaction's manipulation has minimal effect on the average
}
On-Chain Monitoring
A defense system is incomplete without monitoring. Forta Network is a decentralized detection network with bots monitoring on-chain activity.
// Forta bot: detecting potential flash loan attacks
async function handleTransaction(txEvent) {
const findings = [];
// Check for flash loan calldata in the transaction
const flashLoanCalls = txEvent.filterFunction([
'flashLoan(address,address,uint256,bytes)',
'flash(address,address,uint256,uint256,bytes)'
]);
if (flashLoanCalls.length > 0) {
// Check for significant state changes in our protocol
const protocolEvents = txEvent.filterLog(PROTOCOL_EVENTS, PROTOCOL_ADDRESS);
if (protocolEvents.length > 0) {
findings.push(Finding.fromObject({
name: "Flash loan + protocol interaction",
description: `Flash loan detected in same tx as protocol events`,
alertId: "FLASH-LOAN-INTERACTION",
severity: FindingSeverity.Medium,
type: FindingType.Suspicious
}));
}
}
return findings;
}
Alerts from Forta can be sent to PagerDuty/Telegram via webhook, giving your team 1–2 minutes to respond before the attack spreads.
Comprehensive Defense Architecture
No single measure is sufficient. An effective defense system is layered:
| Layer | Mechanism | Protects Against |
|---|---|---|
| Oracle | Chainlink primary + TWAP sanity check | Price manipulation |
| Governance | Voting d |







