How to Protect Your Transactions from MEV with GetBlock RPC
Learn how to route a PancakeSwap swap through GetBlock MEV-protected RPC so searchers cannot front-run or sandwich it
Every transaction you send to a public blockchain waits in the mempool before it is mined, and while it waits, anyone can read it. Searchers run bots that scan that queue for trades worth exploiting — buying ahead of your swap to push the price up, selling into it afterward, or wrapping it in a pair of their own trades so you fill at the worst price in the block. This is Maximal Extractable Value, and on a DEX swap it comes straight out of your output.
The frustrating part is that nothing in your code is wrong: the vulnerability is simply that your transaction was visible while pending(you can use txpool_content to see pending transactions). Every one of those attacks depends on that visibility, and nothing else.
In this guide, you will learn how to protect your transactions from MEV on BNB Smart Chain by building a PancakeSwap swap CLI that routes through a GetBlock BSC endpoint with the MEV Protection add-on enabled.
What you'll build
A swap command — npm run swap -- --amount <BNB> — built around a main() function that:
Quotes the BNB → USDT swap on PancakeSwap V2 with
getAmountsOut.Derives a minimum-received floor from your slippage tolerance.
Estimates gas and adds a safety buffer before signing.
Sends
swapExactETHForTokensthrough your MEV-protected endpoint.Waits for the receipt and reports the USDT actually received.
Prerequisites
Node.js 18+ — the project uses ES modules and top-level
async.A GetBlock account — free to create.
A BSC endpoint with MEV Protection — created in the dashboard, with the add-on enabled.
A funded BSC wallet — roughly $2 of BNB is plenty.
Use a throwaway key, never a wallet holding real funds.
Basic JavaScript knowledge.
Project Setup
Create your MEV-protected endpoint
In your GetBlock dashboard, create a BNB Smart Chain endpoint on Mainnet, then enable the MEV Protection add-on for it. Copy the JSON-RPC URL, which looks like:
GetBlock routes transactions sent to this endpoint through a private mempool. The transaction goes straight to the builder instead of being broadcast to the public queue.
Build the swap
Create index.js. The whole file is below; the comments mark the three decisions that matter.
Notice what is not in this file. There is no bundle format, no relay-specific RPC method, no extra signature, and no SDK. swapExactETHForTokens is called exactly as it would be against any BSC node, and ethers broadcasts it with a plain eth_sendRawTransaction. The protection comes from BSC_MEV_RPC pointing at an MEV-protected endpoint — that single line is the whole integration.
Run the swap
--amount is required, so a bare command can never spend money you did not name. --slippage defaults to 0.5.
At the time of writing, 0.0017 BNB is about $1. Expected output:
The swap filled at 1.021778 USDT against an expected 1.021781 — a gap of three millionths of a USDT, and comfortably above the 1.016672 floor. There was no sandwich to absorb, because there was never a pending transaction for a bot to find.
Understanding the response
expected
decimal string
The router's quote for your input at current reserves, before any price movement.
min received
decimal string
The floor your transaction enforces on-chain. The swap reverts rather than fill below this.
wallet
address
The account derived from PRIVATE_KEY that signs and receives.
tx
32-byte hash
The transaction hash, computed at signing and valid to look up once mined.
mined in block
integer
The block that included the swap, from the transaction receipt.
received
decimal string
Your actual fill, measured as the USDT balance difference across the swap. Compare it to expected to see your real slippage.
Troubleshooting
Transaction reverts with gasUsed just below the gas limit
Ethers sent the bare eth_estimateGas result, which is the minimum gas that succeeds at estimation time. Pool state moved before inclusion and an inner call hit EIP-150's 63/64 limit.
Set an explicit gasLimit with headroom, as this guide does with (estimate * 125n) / 100n. Unused gas is refunded.
PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT
The price moved further than your slippage tolerance between the quote and inclusion.
Raise --slippage, or re-run when the pool is calmer. Do not raise it beyond what you would accept losing.
PancakeRouter: EXPIRED
The 5-minute deadline passed before the transaction was included.
Increase the deadline window, or check whether the transaction is stuck at too low a gas price.
Missing PRIVATE_KEY or Missing BSC_MEV_RPC
.env is absent or incomplete.
Create .env with both values. Confirm dotenv/config is imported at the top of index.js.
insufficient funds for intrinsic transaction cost
The wallet cannot cover --amount plus gas.
Fund the wallet, or lower --amount.
Transaction stays pending for a long time
BSC gas price defaults to the floor of 0.05 gwei.
Pass an explicit higher gasPrice in the transaction overrides.
Missing --amount
The flag was omitted, or -- was left out of the npm invocation.
Run npm run swap -- --amount 0.0017. The bare -- passes the flags through to the script.
Conclusion
You built a PancakeSwap CLI that quotes a BNB → USDT swap, enforces a slippage floor, sizes its gas with a safety buffer, and broadcasts through a GetBlock endpoint carrying the MEV Protection add-on. The transaction code is ordinary ethers — the protection came entirely from the endpoint URL, which routed the swap to a private mempool where searchers could not see it. Slippage tolerance and MEV Protection remain complementary: one caps what an honest price move can cost you, the other removes the opportunity for a deliberate attack.
Resources
Last updated
Was this helpful?