<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Merunas Grincalaitis</title>
    <description>The latest articles on DEV Community by Merunas Grincalaitis (@mevdao).</description>
    <link>https://dev.to/mevdao</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4201256%2F5603ae7e-e0ec-4c1c-ac67-84a420927b82.png</url>
      <title>DEV Community: Merunas Grincalaitis</title>
      <link>https://dev.to/mevdao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mevdao"/>
    <language>en</language>
    <item>
      <title>How to Test an MEV Bot on a Mainnet Fork With Anvil</title>
      <dc:creator>Merunas Grincalaitis</dc:creator>
      <pubDate>Thu, 22 Oct 2026 21:42:37 +0000</pubDate>
      <link>https://dev.to/mevdao/how-to-test-an-mev-bot-on-a-mainnet-fork-with-anvil-32j9</link>
      <guid>https://dev.to/mevdao/how-to-test-an-mev-bot-on-a-mainnet-fork-with-anvil-32j9</guid>
      <description>&lt;p&gt;The most expensive way to test an MEV bot is on mainnet with real money. A bug in the swap math, a wrong token decimal, an approval missing in the contract, and the "test" costs a few hundred dollars in gas or a lot more in bad trades.&lt;/p&gt;

&lt;p&gt;The cheap way is a mainnet fork. You run a local copy of Ethereum that starts from the real chain state at a block you choose. Every pool, every token balance and every contract is there, but the ETH is fake and nothing you do touches the real chain. Foundry's Anvil makes this really easy.&lt;/p&gt;

&lt;p&gt;This is the setup I'd recommend for testing any bot: arbitrage, liquidation, sniping, anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Foundry and start a fork
&lt;/h2&gt;

&lt;p&gt;If you don't have Foundry yet, install it from &lt;a href="https://www.getfoundry.sh" rel="noopener noreferrer"&gt;getfoundry.sh&lt;/a&gt;. Then you need an archive-capable RPC URL. A free tier from a node provider works to start, or your own node if you have one.&lt;/p&gt;

&lt;p&gt;Start the fork:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;anvil &lt;span class="nt"&gt;--fork-url&lt;/span&gt; &lt;span class="nv"&gt;$ETH_RPC_URL&lt;/span&gt; &lt;span class="nt"&gt;--fork-block-number&lt;/span&gt; 21000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives you a local node on &lt;code&gt;http://127.0.0.1:8545&lt;/code&gt; with mainnet state as of that block. Anvil fetches the state it needs from your RPC as you go and caches it, so the first calls are slower than the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always pin the block number.&lt;/strong&gt; If you don't, you fork from the latest block, and every test run starts from a different state. Pinned blocks make your tests reproducible, and Anvil can reuse its cache. The &lt;a href="https://www.getfoundry.sh/anvil/forking" rel="noopener noreferrer"&gt;forking docs&lt;/a&gt; cover the options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't use the default accounts with real keys
&lt;/h2&gt;

&lt;p&gt;Anvil starts with ten accounts, each with 10,000 fake ETH, from a well-known test mnemonic. Those keys are public. Everyone has them. If you ever use one of them on a real network by accident, whatever's in it gets taken immediately.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.getfoundry.sh/anvil" rel="noopener noreferrer"&gt;Anvil docs&lt;/a&gt; warn about this. Use your own mnemonic for forks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;anvil &lt;span class="nt"&gt;--fork-url&lt;/span&gt; &lt;span class="nv"&gt;$ETH_RPC_URL&lt;/span&gt; &lt;span class="nt"&gt;--fork-block-number&lt;/span&gt; 21000000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--mnemonic&lt;/span&gt; &lt;span class="s2"&gt;"your own test mnemonic that is never used on mainnet"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And keep your real bot keys out of the test environment completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The custom methods that make forks useful
&lt;/h2&gt;

&lt;p&gt;Anvil has a set of &lt;a href="https://www.getfoundry.sh/anvil/custom-methods" rel="noopener noreferrer"&gt;custom RPC methods&lt;/a&gt; beyond normal Ethereum JSON-RPC. These are the ones I use most for bots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impersonate any address
&lt;/h3&gt;

&lt;p&gt;You can send transactions as any address without its private key. That's how you get tokens for testing, by impersonating a whale, or how you replay a transaction from a real user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast rpc anvil_impersonateAccount &lt;span class="nv"&gt;$WHALE&lt;/span&gt;
cast send &lt;span class="nv"&gt;$USDC&lt;/span&gt; &lt;span class="s2"&gt;"transfer(address,uint256)"&lt;/span&gt; &lt;span class="nv"&gt;$MY_BOT&lt;/span&gt; 1000000000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; &lt;span class="nv"&gt;$WHALE&lt;/span&gt; &lt;span class="nt"&gt;--unlocked&lt;/span&gt;
cast rpc anvil_stopImpersonatingAccount &lt;span class="nv"&gt;$WHALE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or start Anvil with &lt;code&gt;--auto-impersonate&lt;/code&gt; to allow it for every address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set balances, code and storage directly
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast rpc anvil_setBalance &lt;span class="nv"&gt;$MY_BOT&lt;/span&gt; 0xDE0B6B3A7640000   &lt;span class="c"&gt;# 1 ETH&lt;/span&gt;
cast rpc anvil_setCode &lt;span class="nv"&gt;$ADDRESS&lt;/span&gt; &lt;span class="nv"&gt;$BYTECODE&lt;/span&gt;
cast rpc anvil_setStorageAt &lt;span class="nv"&gt;$ADDRESS&lt;/span&gt; &lt;span class="nv"&gt;$SLOT&lt;/span&gt; &lt;span class="nv"&gt;$VALUE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;anvil_setCode&lt;/code&gt; is great for swapping a contract for a modified version, for example a mock oracle you can move whenever you want. That's how you test a liquidation bot: change the price, see if your bot finds the position and closes it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Control mining
&lt;/h3&gt;

&lt;p&gt;This is the important one for MEV. By default, Anvil mines a block for every transaction instantly. That's useless if your bot needs to react to pending transactions. So turn it off:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;anvil &lt;span class="nt"&gt;--fork-url&lt;/span&gt; &lt;span class="nv"&gt;$ETH_RPC_URL&lt;/span&gt; &lt;span class="nt"&gt;--fork-block-number&lt;/span&gt; 21000000 &lt;span class="nt"&gt;--no-mining&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now transactions sit in Anvil's pool until you mine. You can see them with &lt;code&gt;txpool_content&lt;/code&gt;, the same way your bot would watch a mempool, and then mine when you're ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast rpc txpool_content
cast rpc anvil_mine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets you simulate the real flow: a "victim" transaction arrives in the pool, your bot sees it, builds its response, and you mine one block to see the result. You can also use &lt;code&gt;--block-time 12&lt;/code&gt; for regular 12-second blocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Snapshots
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast rpc evm_snapshot     &lt;span class="c"&gt;# returns an id&lt;/span&gt;
&lt;span class="c"&gt;# ... run your test ...&lt;/span&gt;
cast rpc evm_revert &lt;span class="nv"&gt;$SNAPSHOT_ID&lt;/span&gt;   &lt;span class="c"&gt;# back to the snapshot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Snapshot before each test case and revert afterwards. You can run the same scenario a hundred times without restarting Anvil or fetching state again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traces
&lt;/h3&gt;

&lt;p&gt;Start Anvil with &lt;code&gt;--print-traces&lt;/code&gt; and you'll see the full call trace for every transaction in the terminal. When your bot's transaction reverts with a useless error, this tells you which call failed and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replay a real opportunity
&lt;/h2&gt;

&lt;p&gt;This is where forks really help. Find a real MEV transaction on Etherscan, a liquidation or an arbitrage that another bot won. Note its block number, then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork at the block &lt;strong&gt;before&lt;/strong&gt; it: &lt;code&gt;--fork-block-number &amp;lt;block - 1&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Disable mining.&lt;/li&gt;
&lt;li&gt;Send the transactions that came before it in that block (impersonating their senders), so the state is the same as when the opportunity appeared.&lt;/li&gt;
&lt;li&gt;Run your bot and see if it finds the same opportunity, and how much it would have made.&lt;/li&gt;
&lt;li&gt;Compare your gas usage to the winner's.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also inspect any historical transaction directly with &lt;code&gt;cast run&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cast run &lt;span class="nv"&gt;$TX_HASH&lt;/span&gt; &lt;span class="nt"&gt;--rpc-url&lt;/span&gt; &lt;span class="nv"&gt;$ETH_RPC_URL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That replays the transaction locally and prints its trace, which is great for understanding what a competitor's contract actually does.&lt;/p&gt;

&lt;p&gt;Do this for twenty historical opportunities and you'll learn more about your strategy than from a month of reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Forge tests for the contract
&lt;/h2&gt;

&lt;p&gt;For the on-chain part of the bot, write Foundry tests that run against a fork:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function setUp() public {
    vm.createSelectFork(vm.envString("ETH_RPC_URL"), 21_000_000);
    deal(USDC, address(bot), 1_000e6);
}

function test_arbitrageIsProfitable() public {
    uint256 before = IERC20(WETH).balanceOf(address(bot));
    bot.execute(route);
    assertGt(IERC20(WETH).balanceOf(address(bot)), before);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;deal&lt;/code&gt; from forge-std sets a token balance for you, so you don't need to find a whale. Add tests for the failure cases too: what happens if the price moved, if the pool is empty, if the token takes a fee. Those are the ones that lose real money.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a fork can't tell you
&lt;/h2&gt;

&lt;p&gt;A fork is great for checking that your logic and contracts work. It doesn't tell you whether you'll &lt;strong&gt;win&lt;/strong&gt; on mainnet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No competition.&lt;/strong&gt; On your fork, you're the only bot. On mainnet, ten others see the same opportunity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No builder auction.&lt;/strong&gt; Your bundle doesn't compete for inclusion. To learn how that part works, read &lt;a href="https://mevdao.org/blog/flashbots-bundles-explained-how-to-send-eth-sendbundle-and-why-yours-isn-t-landi" rel="noopener noreferrer"&gt;Flashbots bundles explained&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No latency.&lt;/strong&gt; Real bots fail because they're 200ms too slow. A fork won't show that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your RPC is the bottleneck.&lt;/strong&gt; Forks fetch state on demand, so heavy tests can hit rate limits on free RPC plans.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So use the fork to make sure the bot is &lt;em&gt;correct&lt;/em&gt;, then go live with small size to find out if it's &lt;em&gt;competitive&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  My testing checklist before going live
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Contract tests pass on a fork, including failure cases&lt;/li&gt;
&lt;li&gt;[ ] Bot finds and handles at least ten replayed historical opportunities&lt;/li&gt;
&lt;li&gt;[ ] Gas usage is close to (or lower than) the bots that won those opportunities&lt;/li&gt;
&lt;li&gt;[ ] Profit calculation includes gas and the builder payment&lt;/li&gt;
&lt;li&gt;[ ] No private key from the test setup is used anywhere real&lt;/li&gt;
&lt;li&gt;[ ] Kill switch and max position size are tested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building a liquidation bot, I wrote about the strategy side in &lt;a href="https://mevdao.org/blog/how-liquidation-bots-work-on-aave-and-why-they-re-hard-to-win" rel="noopener noreferrer"&gt;how liquidation bots work on Aave&lt;/a&gt;. For arbitrage, start with &lt;a href="https://mevdao.org/blog/how-to-build-a-profitable-mev-arbitrage-bot" rel="noopener noreferrer"&gt;how to build a profitable MEV arbitrage bot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you want me to build or review a bot for you, message me on &lt;a href="https://t.me/merunas" rel="noopener noreferrer"&gt;Telegram&lt;/a&gt;. The ready-made MEVDAO tools, the Sniper Bot, Sniping Group and Token Rescue Bot, are on the &lt;a href="https://mevdao.org/#features" rel="noopener noreferrer"&gt;features page&lt;/a&gt;. Join the MEV Secrets email list right below for weekly tips.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://mevdao.org/blog/how-to-test-an-mev-bot-on-a-mainnet-fork-with-anvil" rel="noopener noreferrer"&gt;MEV DAO blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>web3</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flashbots Bundles Explained: How to Send eth_sendBundle and Why Yours Isn't Landing</title>
      <dc:creator>Merunas Grincalaitis</dc:creator>
      <pubDate>Thu, 22 Oct 2026 21:42:27 +0000</pubDate>
      <link>https://dev.to/mevdao/flashbots-bundles-explained-how-to-send-ethsendbundle-and-why-yours-isnt-landing-2de8</link>
      <guid>https://dev.to/mevdao/flashbots-bundles-explained-how-to-send-ethsendbundle-and-why-yours-isnt-landing-2de8</guid>
      <description>&lt;p&gt;Almost every MEV bot on Ethereum, whether it's an arbitrage bot, a sniper or a rescue script, ends up sending bundles. And almost every developer who sends their first bundle has the same experience: the request returns a bundle hash, everything looks fine, and nothing ever shows up on-chain.&lt;/p&gt;

&lt;p&gt;This guide covers what a bundle is, how to send one properly, and a practical checklist for figuring out why yours isn't landing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a bundle is
&lt;/h2&gt;

&lt;p&gt;A bundle is an ordered list of signed transactions that you send privately to a block builder instead of broadcasting them to the public mempool. The builder will include the whole bundle, in exactly that order, in one block, or it won't include any of it.&lt;/p&gt;

&lt;p&gt;Flashbots popularized this. Their &lt;a href="https://docs.flashbots.net/flashbots-auction/quick-start" rel="noopener noreferrer"&gt;Quick Start&lt;/a&gt; describes the flow: searchers send bundles to builders, builders simulate them to make sure they don't revert, build full blocks, and deliver those blocks to validators through mev-boost relays. Validators running mev-boost pick the most valuable block offered to them.&lt;/p&gt;

&lt;p&gt;Three properties make bundles so useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Atomic.&lt;/strong&gt; All of the transactions land together or none do. That's what makes things like sponsored wallet rescues possible, where one transaction funds an account and the next ones spend that ETH in the same block. I covered that in &lt;a href="https://mevdao.org/blog/how-to-rescue-tokens-from-a-compromised-wallet-with-a-sweeper-bot-flashbots-guid" rel="noopener noreferrer"&gt;how to rescue tokens from a compromised wallet with a sweeper bot&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordered.&lt;/strong&gt; You control the sequence, which is how backruns and same-block snipes work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Private and revert-protected.&lt;/strong&gt; Bundles aren't visible in the public mempool before inclusion, and failed bundles don't land on-chain, so you don't pay gas for a trade that didn't work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to send a bundle
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The endpoints
&lt;/h3&gt;

&lt;p&gt;Flashbots has two main endpoints on mainnet, and mixing them up is a common first mistake. Per the &lt;a href="https://docs.flashbots.net/guide-send-tx-bundle" rel="noopener noreferrer"&gt;Flashbots guide on sending transactions and bundles&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rpc.flashbots.net&lt;/code&gt; is &lt;strong&gt;Flashbots Protect&lt;/strong&gt;, a drop-in wallet RPC for regular users. It takes normal &lt;code&gt;eth_sendRawTransaction&lt;/code&gt; calls. It does not take bundles.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;relay.flashbots.net&lt;/code&gt; is for searchers and bots. It accepts bundles and private transactions through Flashbots-specific methods. It does not support regular Ethereum RPC methods, so you still need a normal node for nonces, gas estimates and receipts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For testing, there's also a Sepolia relay at &lt;code&gt;relay-sepolia.flashbots.net&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The signing key
&lt;/h3&gt;

&lt;p&gt;Every request to the relay is signed with an ECDSA key that identifies you as a searcher. The signature goes in the &lt;code&gt;X-Flashbots-Signature&lt;/code&gt; header as &lt;code&gt;address:signature&lt;/code&gt;, where the signature is over the JSON body. This key doesn't hold funds and shouldn't be your trading key. Flashbots uses it to build a reputation for you over time, and higher-reputation searchers get better access when the network is congested. So reuse the same identity key instead of generating a new one every run.&lt;/p&gt;

&lt;h3&gt;
  
  
  The eth_sendBundle request
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint" rel="noopener noreferrer"&gt;JSON-RPC docs&lt;/a&gt; describe the payload. The core fields are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;txs&lt;/code&gt;: an array of signed raw transactions, in order.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blockNumber&lt;/code&gt;: the hex block number this bundle is valid for.&lt;/li&gt;
&lt;li&gt;Optional: &lt;code&gt;minTimestamp&lt;/code&gt; and &lt;code&gt;maxTimestamp&lt;/code&gt;, &lt;code&gt;revertingTxHashes&lt;/code&gt; (transactions that are allowed to revert without killing the bundle), &lt;code&gt;replacementUuid&lt;/code&gt; (to replace or cancel a bundle later) and &lt;code&gt;builders&lt;/code&gt; (a list of other registered builders that should also receive the bundle).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same docs list limits of 100 transactions and 300,000 bytes per bundle.&lt;/p&gt;

&lt;p&gt;A minimal request body looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eth_sendBundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"txs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0x02f8..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x02f8..."&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"blockNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0x1499a2c"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're in JavaScript, the official &lt;a href="https://github.com/flashbots/ethers-provider-flashbots-bundle/" rel="noopener noreferrer"&gt;ethers-provider-flashbots-bundle&lt;/a&gt; library handles signing and gives you &lt;code&gt;simulate()&lt;/code&gt; and &lt;code&gt;sendBundle()&lt;/code&gt; helpers. Note that its README says it's designed for an existing ethers.js v5 installation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Target the next block, and resubmit every block
&lt;/h3&gt;

&lt;p&gt;A bundle is valid for one block. If you target block N+1 and it isn't included there, it's gone. The library README is explicit that if your bundle should be valid until it's mined, you need to resubmit for every block, and the target should always be a future block, never the current one.&lt;/p&gt;

&lt;p&gt;Resubmitting each block is also your chance to re-check the opportunity, update fees to the new base fee, and re-sign with the correct nonce.&lt;/p&gt;

&lt;h3&gt;
  
  
  mev_sendBundle and MEV-Share
&lt;/h3&gt;

&lt;p&gt;Flashbots also has &lt;code&gt;mev_sendBundle&lt;/code&gt;, a newer format that supports MEV-Share, where you can backrun user transactions that are only partially revealed through hints. Their &lt;a href="https://writings.flashbots.net/searching-on-mev-share" rel="noopener noreferrer"&gt;MEV-Share searcher writeup&lt;/a&gt; explains the strategies. If you're just starting, &lt;code&gt;eth_sendBundle&lt;/code&gt; is the simple option and is what most examples use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Always simulate first
&lt;/h2&gt;

&lt;p&gt;Before you send anything, simulate it with &lt;code&gt;eth_callBundle&lt;/code&gt; (the library's &lt;code&gt;simulate()&lt;/code&gt; method). The simulation runs your signed transactions in order on top of a given block and returns gas used, fees paid and coinbase payments for each transaction.&lt;/p&gt;

&lt;p&gt;This catches the majority of problems before they cost you an opportunity. The &lt;a href="https://docs.flashbots.net/flashbots-auction/advanced/troubleshooting" rel="noopener noreferrer"&gt;Flashbots troubleshooting guide&lt;/a&gt; recommends simulating, logging the results, and keeping a record of every bundle and its signed transactions, because a bundle that fails leaves no trace on Etherscan to debug from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your bundle isn't being included: the checklist
&lt;/h2&gt;

&lt;p&gt;The Flashbots troubleshooting guide lists five reasons a bundle doesn't land, in the order you should check them.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. A transaction in the bundle reverts
&lt;/h3&gt;

&lt;p&gt;If any transaction reverts (and isn't listed in &lt;code&gt;revertingTxHashes&lt;/code&gt;), the whole bundle is dropped. Common causes: wrong nonce, insufficient balance, a stale price that makes your slippage check fail, a deadline that's already passed, or a token transfer that the token contract blocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; simulate against the block you're targeting and read the per-transaction results.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. You're not paying enough for the blockspace
&lt;/h3&gt;

&lt;p&gt;Your transactions must pay at least the base fee, or the block would be invalid. Beyond that, the builder compares what your bundle pays with what it would earn from other transactions using the same gas. The docs give a simple example: if your bundle pays a 1 gwei priority fee but the cheapest transaction in the block pays 2 gwei, the builder is better off leaving your bundle out.&lt;/p&gt;

&lt;p&gt;What matters is the &lt;strong&gt;effective priority fee&lt;/strong&gt;: everything the bundle pays the builder (priority fees plus any direct ETH transfers to the block's coinbase), divided by the gas it uses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; pay more, or use less gas for the same result. Gas optimization is a bid in disguise.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A competitor bid more for the same opportunity
&lt;/h3&gt;

&lt;p&gt;Builders roughly simulate each bundle at the top of the block, sort by effective priority fee, and then add bundles one by one as long as they still work. If another bundle that touches the same state goes first, yours may revert, collide on a nonce, or pay less than it did in isolation. Then it's dropped.&lt;/p&gt;

&lt;p&gt;The auction is blind, so you can't see competing bids in advance. You can look afterward: the library's &lt;code&gt;getConflictingBundle()&lt;/code&gt; helper re-simulates the target block to find which bundle conflicted with yours and how much it paid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; compare your effective priority fee with the winner's. If you're consistently outbid, the opportunity may be too competitive. In that case, a less crowded strategy beats a higher bid. My take on that is in &lt;a href="https://mevdao.org/blog/how-to-build-a-profitable-mev-arbitrage-bot" rel="noopener noreferrer"&gt;how to build a profitable MEV arbitrage bot&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Your bundle arrived too late
&lt;/h3&gt;

&lt;p&gt;Your bundle has to reach the builder, get simulated, go into a block, and get through a relay to the validator, all before the slot. The troubleshooting guide notes each of those steps can take around 1 to 2 seconds. There's also a window where your node still thinks the chain is at block X while the rest of the network has already seen X+1, so you're targeting a block that's already been built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; cut your own processing time, use low-latency, well-synced nodes, and send your bundle as early as you can in the slot.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The validator isn't running mev-boost
&lt;/h3&gt;

&lt;p&gt;mev-boost is opt-in. If the validator for a slot doesn't run it, or isn't connected to a relay your builder submits to, no bundle will land in that block. Research on the builder market, such as &lt;a href="https://arxiv.org/html/2407.13931" rel="noopener noreferrer"&gt;this 2024 study&lt;/a&gt;, found that the large majority of blocks since the Merge come through mev-boost, but not all of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; nothing to fix. Resubmit for the next block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Send to more than one builder
&lt;/h2&gt;

&lt;p&gt;Flashbots is one builder among several. The builder market is concentrated in a handful of players, and their share changes over time. You can see current relay and builder shares on &lt;a href="https://www.relayscan.io/overview?t=24h" rel="noopener noreferrer"&gt;relayscan.io&lt;/a&gt; and slot-level data on &lt;a href="https://mevboost.pics/data" rel="noopener noreferrer"&gt;mevboost.pics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you only send to one builder, you only get into blocks that builder wins. You can use the &lt;code&gt;builders&lt;/code&gt; field to have Flashbots share your bundle with other registered builders, and many builders run their own bundle endpoints. Check each builder's documentation for its exact API before relying on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get refunds when you overpay
&lt;/h2&gt;

&lt;p&gt;Eligible bundles that land in blocks built by BuilderNet (the block-building network Flashbots operates together with partners) can earn refunds of part of what they paid, based on how much they contributed to the block's value. The rules are in the &lt;a href="https://buildernet.org/docs/refunds" rel="noopener noreferrer"&gt;BuilderNet refunds documentation&lt;/a&gt;. The Flashbots RPC docs include &lt;code&gt;flashbots_getFeeRefundsByRecipient&lt;/code&gt; and related methods so you can see what you've earned, and &lt;code&gt;flashbots_setFeeRefundRecipient&lt;/code&gt; to send refunds to a different address. It's worth checking, especially if you bid aggressively.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;relay.flashbots.net&lt;/code&gt; for bundles, with a stable identity key.&lt;/li&gt;
&lt;li&gt;Simulate with &lt;code&gt;eth_callBundle&lt;/code&gt; every time.&lt;/li&gt;
&lt;li&gt;Target the next block and resubmit every block.&lt;/li&gt;
&lt;li&gt;Check the five failure reasons in order: reverts, fee too low, outbid, too late, no mev-boost.&lt;/li&gt;
&lt;li&gt;Send to multiple builders.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you'd rather not build all of this yourself, the &lt;a href="https://mevdao.org/#features" rel="noopener noreferrer"&gt;MEVDAO Sniper Bot and Token Rescue Bot&lt;/a&gt; already handle bundle building, simulation and submission for sniping and wallet rescues. They're included in the &lt;a href="https://mevdao.org/#pricing" rel="noopener noreferrer"&gt;MEVDAO subscription&lt;/a&gt; with a &lt;a href="https://mevdao.org/subscribe" rel="noopener noreferrer"&gt;3-day free trial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more guides like this, join the free MEV Secrets email list below. And if you want a custom MEV bot built, &lt;a href="https://t.me/merunas" rel="noopener noreferrer"&gt;message me on Telegram&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://mevdao.org/blog/flashbots-bundles-explained-how-to-send-eth-sendbundle-and-why-yours-isn-t-landi" rel="noopener noreferrer"&gt;MEV DAO blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
