Bundling Transactions with Flashbots

In this two-part series, I’m sharing what I’ve learned about the Ethereum Mempool, starting with Flashbots. For this post, I’ve deployed an NFT contract to the Goerli network at the address: 0x556685dBcccDBec95bD4d96171A49b906eE1589b

This contract has a “mint” function that can be externally called. Clicking on the “Contract” tab on Etherscan reveals the contract’s runtime bytecode. It’ll be largely unreadable, like this:

Etherscan reveals the contract's runtime bytecode

Since the contract source code hasn’t been verified on Etherscan, we can’t see the Solidity here, per usual. This raises a question: how do we construct the calldata to use within our bundle?

EVM Lifecycle:

Whether you’re writing smart contracts in Solidity or Vyper, your code must be compiled into bytecode before it’s deployed to the EVM. This bytecode represents a series of opcode instructions that the EVM then executes.

Calldata:

When a contract function is called, calldata is included, and it specifies the target function signature along with any arguments that need to be passed in. Now the question is how the EVM knows what bytecode to execute depending on the contract’s function.

The bytecode created from Solidity contracts represents all of the contract’s code. A contract may have one or more functions that can be called once it is deployed.

The canonical representation of a function signature is the function name along with the function argument types, for example “mint(uint256).” This is then hashed using the Keccak256 algorithm to produce 36 bytes of calldata. The first four bytes of the calldata represent the unique function selector, while the remaining 32 bytes correspond to the input argument.

Consider this function signature:
0xa0712d680000000000000000000000000000000000000000000000000000000000000005

Here, the function selector is a0712d68 and the input argument is as follows: 000000000000000000000000000000000000000000000000000000000000000​​5

So, the calldata equates to calling mint(5).

Putting it all together:

Great! So revisiting the code from the previous post in this series with our newfound knowledge, a bundle may look like this:


const bundle = await flashbotsProvider.sendBundle([
      {
        transaction: {
          chainId: CHAIN_ID,
          type: 2,
          value: ETHER.div(100).mul(3),
          data: "0xa0712d680000000000000000000000000000000000000000000000000000000000000005", //  Hex Calldata for function you want to call
          maxFeePerGas: GWEI.mul(3),
          maxPriorityFeePerGas: GWEI.mul(2),
          to: "0x556685dBcccDBec95bD4d96171A49b906eE1589b",
        },
        signer: new Wallet(WALLET_PRIVATE_KEY, provider),
      }
    ], blockNumber + 1);

Real Examples:

So, why would you exert this much effort to submit a few transactions?

Arbitrage:

A searcher notices a price discrepancy between the USDC and WETH pairs on Uniswap and Sushiswap. Acting immediately, they submit a bundle where they:

  1. Buy 1 ether for 1,600 USDC on Uniswap
  2. Sell 1 ether for 1650 USDC on Sushiswap
  3. Profit 50 USDC

Leveraging flash loans from AAVE, one can make an arbitrage trade with much larger sums to produce higher returns. Putting the Max in Maximum Extractable Value.

Sandwiching:

A searcher monitoring a few trading pairs on Uniswap noticed a large transaction pending that would cause a substantial price increase.

By re-ordering the target block, they can submit a bundle of transactions where you buy tokens before the target transaction and sell immediately after the price increase.

Conclusion

When writing this, searchers have captured over $680 million of value by analyzing Defi contracts and utilizing various techniques.

Flashbots - MEV
$687,192,925
Total Extracted MEV (Click for larger image)

Whether you’re trying to retrieve funds from a hacked wallet, arbitraging market inefficiencies, or simply protecting your transactions, it’s essential to dig into the subject of bundling if you’re an active user of Ethereum.

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *