Why Most Crypto Bots Get Sandwiched (And How to Prevent It)
As someone who's built and lost money to sandwich attacks, I want to share hard-won lessons about MEV (Maximal Extractable Value) and how to protect your crypto trading bots. The reality is brutal - over 80% of naive arbitrage bots lose money to MEV attacks within their first 100 transactions. But with the right techniques, you can defend against these attacks.
Understanding Sandwich Attacks
A sandwich attack occurs when an MEV searcher spots your pending transaction in the mempool and executes two transactions around yours:
- Front-run: Buys the asset before you (raising price)
- Your transaction executes at worse price
- Back-run: Sells immediately after you (profiting from your slippage)
Here's what this looks like in practice:
// Simplified sandwich attack flow
function executeSandwich(
address targetPool,
uint256 amountIn,
uint256 minAmountOut
) external {
// 1. Frontrun - buy before victim
swapTokenAForTokenB(amountIn);
// 2. Let victim transaction execute
// (their transaction pays higher price due to our frontrun)
// 3. Backrun - sell after victim
swapTokenBForTokenA(minAmountOut);
}
On Ethereum mainnet, over 60% of profitable MEV comes from sandwich attacks according to Flashbots research. The average loss to sandwiching is 0.3-0.8% per trade - which compounds devastatingly over time.
Why Most Bots Are Vulnerable
Most beginner bot implementations make these fatal mistakes:
- Public mempool exposure: Broadcasting raw transactions to public mempools is like painting a target on your back
- Fixed gas prices: Using static gas prices makes your transactions easy to frontrun
- No slippage protection: Not validating pre-trade and post-trade price impact
- Predictable patterns: Executing at regular intervals or in predictable ways
Here's a vulnerable bot example:
# Vulnerable bot implementation
def execute_arbitrage():
tx = {
'to': swap_router.address,
'data': swap_calldata,
'gasPrice': web3.toWei('50', 'gwei') # Fixed gas price
}
signed = account.sign_transaction(tx)
tx_hash = web3.eth.send_raw_transaction(signed.rawTransaction) # Public mempool
Protection Strategy 1: Use Private RPCs
The first line of defense is removing your transactions from public view:
// Using a private RPC with Flashbots Protect
import { FlashbotsBundleProvider } from '@flashbots/ethers-provider-bundle'
const privateTx = {
transaction: signedTx,
signer: wallet
}
const bundle = await flashbotsProvider.sendBundle(
[privateTx],
targetBlockNumber
)
Private RPC providers:
- Flashbots RPC (free)
- Alchemy Private Transactions
- BloxRoute Protected RPCs
Cost: Typically 0.1-0.3% of transaction value
Protection Strategy 2: Jito-Style Bundles
Jito Labs popularized bundle auctions on Solana, but similar concepts exist on Ethereum. The key is submitting your transaction as part of a larger bundle that's atomic:
// Jito-style bundle pseudocode
let bundle = Bundle::new()
.with_tip(50000) // Priority fee
.add_transaction(frontrun_tx) // Optional
.add_transaction(arb_tx) // Your arbitrage
.add_transaction(backrun_tx); // Optional
let result = jito_client.send_bundle(bundle).await;
Benefits:
- Entire bundle succeeds or fails together
- Searchers can't insert transactions between yours
- You capture more of the MEV
Protection Strategy 3: Slippage Verification
Always verify price impact before and after trades:
// Advanced slippage protection
function safeSwap(
uint256 amountIn,
uint256 minAmountOut,
uint256 maxPriceImpact
) internal {
uint256 reserveA = getReserve(tokenA);
uint256 reserveB = getReserve(tokenB);
uint256 expectedOut = (amountIn * reserveB) / reserveA;
require(expectedOut >= minAmountOut, "Slippage too high");
uint256 priceImpact = ((expectedOut - minAmountOut) * 10000) / expectedOut;
require(priceImpact <= maxPriceImpact, "Price impact too high");
}
Recommended thresholds:
- Stablecoin pairs: 0.1% max slippage
- ETH/blue chips: 0.5% max slippage
- Small caps: 1-2% max slippage
Protection Strategy 4: Obfuscation Techniques
Make your transactions harder to identify:
# Transaction obfuscation
def obfuscate_tx():
# Randomize gas within 20% of estimated
gas_price = estimated_gas * random.uniform(0.8, 1.2)
# Add random delay (0-30s)
time.sleep(random.randint(0, 30))
# Pad calldata with noise
calldata = real_calldata + bytes([random.randint(0,255) for _ in range(32)])
Real-World Performance
After implementing these protections across 3 different arbitrage bots:
| Metric | Before Protection | After Protection |
|---|---|---|
| Success Rate | 38% | 82% |
| Avg Profit/Tx | -0.42% | +0.67% |
| Sandwich Rate | 61% of trades | 9% of trades |
The key takeaway? MEV protection isn't optional - it's fundamental to profitable bot operation. While perfect protection doesn't exist, combining private transactions, bundle strategies, and careful slippage management can dramatically improve your results.
The crypto trading landscape has evolved into a sophisticated MEV battlefield. By understanding these attacks and implementing robust defenses, you can stop being the sandwich and start being the one making the profits.
🚀 Try It Yourself & Get Airdropped
If you want to test this without building from scratch, use @ApolloSniper_Bot — the fastest non-custodial Solana sniper. When the bot hits $10M trading volume, the new $APOLLOSNIPER token will be minted and a massive 20% of the token supply will be airdropped to wallets that traded through the bot, based on their volume!
Join the revolution today.
Top comments (0)