Rust client library for Flashbots MEV-Share

Overview

Flashbots MEV-Share Client

License: MIT

Rust client library for Flashbots MEV-Share. Based on the MEV-Share specs and the TypeScript reference implementation.

Usage

In Cargo.toml:

[dependencies]
mev_share_rs = "0.1.0"

Client initialization

First, client initialization may fail for various reasons and therefore returns a Result. The quickest way to initialize a client, is to pass it a Signer to use for Flashbots authentication and a Provider.

use ethers::prelude::*;
use mev_share_rs::prelude::*;

let auth_wallet = LocalWallet::random();
let provider = Provider::connect("https://rpc.example/api_key");

In order to know which MEV-Share endpoint to query, the client needs to know which chain id you're on. You can either .await the client to fetch it from the provider:

let client = MevShareClient::new(auth_wallet, provider).await?;

or you can supply it yourself:

let client = MevShareClient::new_with_chain_id(auth_wallet, provider, 1)?;

Subscribing to MEV-Share events

Once you have a client, you can listen to the bundles submitted to the MEV-Share Flashbots relayer:

use mev_share_rs::prelude::*;

let mut stream = client.subscribe_bundles().await?;
while let Some(event) = stream.next().await {
    let bundle = event?; // upstream any error
    println!("Bundle received: {:?}", bundle);
}

Sending private transactions

You can also send private transactions and bundles with the MEV-Share API: mev_sendBundle/mev_simBundle and the latest version of eth_sendPrivateTransaction use an upgraded bundle format than the order eth_sendBundle/eth_callBundle, in order to allow users to specify privacy and other guarantees. You can send a private transaction:

use mev_share_rs::prelude::*;

let pending_tx = client.send_private_transaction(
    SendTransactionParams::builder()
        // a signed `TypedTransaction`
        .tx(tx)
        // drop after 20 blocks
        .max_block_number(current_block + 20)
        .preferences(
            // what to disclose 
            Some(set![
                Hint::Hash, 
                Hint::Calldata, 
                Hint::Logs, 
                Hint::ContractAddress, 
                Hint::FunctionSelector
            ]),
            // to whom
            Some(set![
                Builder::Flashbots, 
            ]),
        )
        .build()
).await?;

wait for its inclusion in a block:

let (receipt, block) = pending_tx.inclusion().await?;
println!("Transaction included in block {}", block);

and/or handle errors:

match pending_tx.inclusion().await {
    Err(Error::TransactionTimeout) =>
        println!("the transaction was not included after 25 blocks or params.max_block_number"),
    Err(Error::TransactionReverted) =>
        println!("the transaction was reverted"),
    Ok((receipt, block)) =>
        println!("Transaction included in block {}", block),
}

If you're upstreaming the errors:

client
    .send_private_transaction(tx_request)
    .await?
    .inclusion()
    .await?;

Sending bundles

Similarly, you can send private bundles to the MEV-Share Flashbots relayer:

let pending_bundle = client.send_private_bundle(
    SendBundleParams::builder()
        .body(vec![
            // a signed `TypedTransaction`
            Signed { tx: tx1, can_revert: false },
            // another signed `TypedTransaction`
            Signed { tx: tx2, can_revert: false },
            // a transaction we found in the mempool
            Tx { hash: tx3 }
        ])
        // drop after 3 blocks
        .inclusion(current_block + 1, Some(current_block + 1 + 3)) 
        // what to disclose to whom
        .privacy(
            // do not share any hints
            None,
            // send only to Flashbots
            Some(set![Builder::Flashbots])
        ),
        )
        .build()
).await?;

await its inclusion in a block:

let (receipt, block) = pending_bundle.inclusion().await?;
println!("Bundle {:?} included in block {}", pending_bundle.hash, block);

and/or handle any eventual error:

match pending_bundle.inclusion().await {
    Err(Error::BundleTimeout(_hashes , max_block)) =>
        println!("bundle {:?} not included after max block {}", pending_bundle.hash, max_block),
    Err(Error::BundleRevert(receipts)) =>
        println!("bundle {:?} reverted: {:?}", pending_bundle.hash, receipts),
    Err(Error::BundleDiscard(landed_receipts)) =>
        println!("bundle has not been included, but some of the transactions landed: {:?}", landed_receipts),
    Ok((receipts, block)) =>
        println!("Bundle {:?} included in block {}", pending_bundle.hash, block),
}

Finally, if you upstream the errors, you can just:

let (bundle_receipts, included_block) = client
    .send_budnle(bundle_request)
    .await?
    .inclusion()
    .await?;

Simulating bundles

If you send too many bad bundles to the Flashbots API, you risk losing your searcher reputation. To avoid that, you can simulate bundles before sending them to Flashbots.

let simulation = client.simulate_bundle(
    bundle_request.clone(),
    SimulateBundleParams::builder()
        .block(current_block + 1)
        .build()
    ).await?;

// avoid sending a reverting bundle
if !simulation.success { return Err(Error::SimulationFailed(simulation)) }

// simulation success! send the bundle to Flashbots
client.send_bundle(bundle_request).await?.inclusion().await?;

Others

get_event_history and get_event_history_info allow you to query bundle submission history: check examples/historycal_stream_data for an example. Finally, examples/send_backrun_bundle gives you an idea on how you can put all of the above to use to listen to transactions hints from the relayer and backrun those you're interested in.

API reference

See [MevShareClient].

Examples

ℹ️ Examples require a .env file (or that you populate your environment directly with the appropriate variables).

cd examples
cp .env.example .env
vim .env

You can run any example using cargo, e.g.:

cargo run --example send_private_tx

Here's the current examples:

  1. send_private_tx.rs: sends a private transaction to the Flashbots MEV-Share relayer
  2. send_bundle.rs: simulates and sends a bundle with hints
  3. historical_stream_data.rs: query bundles history
  4. send_backrun_bundle.rs: subscribe to the Flashbots MEV-Share events stream in order to listen for submitted bundles and transactions and backrun them

Contributing, improvements, and further work

Contributions are welcome! If you'd like to contribute to this project, feel free to open a pull request. Here are a few improvements that are currently being worked on:

  • move examples/ from Goerli to Sepolia as Goerli is being deprecated
  • PendingBundle::inclusion().await could include the check for simulation errors via the flashbots APIs and return (an error) before we have on-chain proof the bundle is not landed (max_block reached or partial on-chain inclusion observed)
  • move from ethers-rs to the newer alloy
  • add unit tests
  • use a JsonRpcClient trait instead of forcing Ws

If you'd like to see more, go ahead and open an issue.

Security

The tool requires a private key for signing transactions. Make sure you don't share your private key or .env file with anyone or commit it to a public repository.

License

This project is licensed under the MIT License

You might also like...
High-level networking library that extends the bevy_replicon library to allow snapshot interpolation and client-side prediction

bevy_replicon_snap A Snapshot Interpolation plugin for the networking solution bevy_replicon in the Bevy game engine. This library is a very rough pro

In addition to encryption library, pure RUST implementation of SSH-2.0 client protocol

In addition to encryption library, pure RUST implementation of SSH-2.0 client protocol

Ethereum JSON-RPC multi-transport client. Rust implementation of web3 library

Ethereum JSON-RPC multi-transport client. Rust implementation of web3 library. ENS address: rust-web3.eth

🐰 Rust client library for the Leap Edge socket service

leap_edge_rs Utility library for connecting and receiving events from Leap Edge. Used for Channels and Pipe. Installation Add this to your Cargo.toml:

Reference library that implements all the necessary functionality for developing a client that is compatible with TAPLE's DLT network.
Reference library that implements all the necessary functionality for developing a client that is compatible with TAPLE's DLT network.

⚠️ TAPLE is in early development and should not be used in production ⚠️ TAPLE Core TAPLE (pronounced T+ 🍎 ['tapəl]) stands for Tracking (Autonomous)

RGB smart contracts: client-facing library & command-line for desktop and mobile

RGB smart contracts RGB is confidential & scalable client-validated smart contracts for Bitcoin & Lightning. It embraces the concepts of private & mut

Coinbase pro client for Rust

Coinbase pro client for Rust Supports SYNC/ASYNC/Websocket-feed data support Features private and public API sync and async support websocket-feed sup

Rust Ethereum 2.0 Client
Rust Ethereum 2.0 Client

Lighthouse: Ethereum 2.0 An open-source Ethereum 2.0 client, written in Rust and maintained by Sigma Prime. Documentation Overview Lighthouse is: Read

rust client libraries to deal with the current cardano mainnet (byron / cardano-sl)

Rust implementation of Cardano primitives, helpers, and related applications Cardano Rust is a modular toolbox of Cardano’s cryptographic primitives,

Owner
Interested in MEV and blockchains
null
Tool to retrieve mev-share events data and scan for refunds onchain

MEV-Share Analysis This repository can be used to retrieve historical events sent to mev-share and scan for any refunds that were sent to the users. T

Yash Atreya 7 Nov 30, 2023
Open source p2p share for devs to share anything with teammates across machines securely.

Secure share Share anything with teammates across machines via CLI. Share is a tool for secure peer-to-peer connections, enabling direct communication

Onboardbase 10 Aug 4, 2023
A Rust client for Flashbots Relay.

flashbots-relay-rs Rust client for interacting directly with the Flashbots Relays. How does it work ? Using a client from the reqwest crate, you can u

Luca G.F. 16 Jun 22, 2022
Using flashbots to mint Otherside metaverse land safely with purchased KYC'd wallets.

Work in progress. Hardcoded to mint 2 lands for 610 APE and approves 100k ape for spending atm, will be updated. Building Install rust, https://rustup

cc 6 May 5, 2022
Utils for flashbots/mempool-dumpster

Intro This is a helper library and cli tool to work with https://github.com/flashbots/mempool-dumpster/, provider of historical mempool data for Ether

Vitaly Drogan 30 Oct 10, 2023
Easily and securely share files from the command line. A fully featured Firefox Send client.

Notice: the default Send host is provided by @timvisee (info). Please consider to donate and help keep it running. ffsend Easily and securely share fi

Tim Visée 6.3k Dec 25, 2022
Open sourcing a profitable MEV Arbitrage Bot written in blazing fast Rust.

Dex Arbitrage - MEV Bot Open sourcing a profitable MEV Arbitrage Bot written in blazing fast Rust. Before Starting I am a self-taught programmer, a co

null 4 Sep 18, 2023
Bootstrap your MEV bot strategies with a simple boilerplate to build on top of.

MEV Template Designed by DeGatchi. Bootstrap your MEV bot strategies with a simple boilerplate to build on top of. How To Use This Template I wrote an

DeGatchi 404 Jan 8, 2023
An MEV back-running template for ethers-rs

MEV price prediction I show how to predict ChainLink price updates from the mempool. For the sake of illustration I work with AAVE V2 price oracles. E

Andrea Simeoni 54 Apr 19, 2023
Mequeue is an executor for MEV bots optimized to be able to process multiple transactions concurrently.

Mequeue Mequeue is an executor for MEV bots optimized to be able to process multiple transactions concurrently. The main goal is to make this executor

null 13 Oct 3, 2023