Code Monkey home page Code Monkey logo

ethers-flashbots's Introduction

Ethers Flashbots

Deprecated

This package is deprecated alongside ethers-rs, and will no longer be maintained.

CI Status Crates.io Docs.rs

An Ethers middleware to send transactions as Flashbots bundles.

Installation

Add ethers-flashbots to your Cargo.toml.

# This is the development version, for the stable release refer
# to crates.io
ethers-flashbots = { git = "https://github.com/onbjerg/ethers-flashbots" }

Usage

use eyre::Result;
use ethers::core::rand::thread_rng;
use ethers::prelude::*;
use ethers_flashbots::*;
use std::convert::TryFrom;
use url::Url;

#[tokio::main]
async fn main() -> Result<()> {
    // Connect to the network
    let provider = Provider::<Http>::try_from("https://mainnet.eth.aragon.network")?;

    // This is your searcher identity
    let bundle_signer = LocalWallet::new(&mut thread_rng());
    // This signs transactions
    let wallet = LocalWallet::new(&mut thread_rng());

    // Add signer and Flashbots middleware
    let client = SignerMiddleware::new(
        FlashbotsMiddleware::new(
            provider,
            Url::parse("https://relay.flashbots.net")?,
            bundle_signer,
        ),
        wallet,
    );

    // Pay Vitalik using a Flashbots bundle!
    let tx = TransactionRequest::pay("vitalik.eth", 100);
    let pending_tx = client.send_transaction(tx, None).await?;

    // Get the receipt
    let receipt = pending_tx
        .await?
        .ok_or_else(|| eyre::format_err!("tx not included"))?;
    let tx = client.get_transaction(receipt.transaction_hash).await?;

    println!("Sent transaction: {}\n", serde_json::to_string(&tx)?);
    println!("Receipt: {}\n", serde_json::to_string(&receipt)?);

    Ok(())
}

See the examples for more in-depth examples.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure that the tests and lints pass (cargo test && cargo clippy -- -D clippy::all && cargo fmt -- --check).

Make sure to add your changes to the "Unreleased" section of the changelog.

Donate

If you would like to support me in my open source journey feel free to send me some Eth or tokens (anything accepted) at bjerg.eth. I appreciate it! ๐Ÿ™‡

ethers-flashbots's People

Contributors

0xdmtri avatar chikko80 avatar dependabot[bot] avatar gakonst avatar ibhagwan avatar juniorbeef avatar mattsse avatar meetmangukiya avatar mouseless-eth avatar naps62 avatar neandertha1er avatar oblique avatar onbjerg avatar r0ohafza avatar timvanscherpenzeel avatar titanbuilder avatar twelfthghast avatar zepedroresende avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethers-flashbots's Issues

rlp: expected input string or byte for *big.Int, decoding into (types.LegacyTx).GasPrice

Simulating a bundle with a Signed(Transaction) (e.g. from mempool) does result in geth node complaining with:

`err="rlp: expected input string or byte for *big.Int, decoding into (types.LegacyTx).GasPrice"

Here is a random example tx:

[src/main.rs:63] &tx = Transaction {
    hash: 0xb272f320f1676befa7e15a8c734c071d52811512c2bb34b475705cf02a88a1ba,
    nonce: 223,
    block_hash: None,
    block_number: None,
    transaction_index: None,
    from: 0xcea4e31e1ca4b6d2391c41a7cb9afc72c81bda3f,
    to: Some(
        0x96ed81c7f4406eff359e27bff6325dc3c9e042bd,
    ),
    value: 0,
    gas_price: Some(
        86624081747,
    ),
    gas: 46258,
    input: Bytes(
        b"\xa2,\xb4e\0\0\0\0\0\0\0\0\0\0\0\0Mt\x1c(\xc4\r\x06(\xe3\xd0\x94S$]\xf7\x7fQ\xfd\xf9]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01",
    ),
    v: 38,
    r: 36074129442019506630029011189037493110736900376526272647848390443457751355846,
    s: 39883350964482382363729019514337022956052712241672243746553175159300450949706,
    transaction_type: Some(
        0,
    ),
    access_list: None,
    max_priority_fee_per_gas: None,
    max_fee_per_gas: None,
    chain_id: None,
}

This is the tx inside bundle.transactions():

[src/main.rs:72] tx = Signed(
    Transaction {
        hash: 0xb272f320f1676befa7e15a8c734c071d52811512c2bb34b475705cf02a88a1ba,
        nonce: 223,
        block_hash: None,
        block_number: None,
        transaction_index: None,
        from: 0xcea4e31e1ca4b6d2391c41a7cb9afc72c81bda3f,
        to: Some(
            0x96ed81c7f4406eff359e27bff6325dc3c9e042bd,
        ),
        value: 0,
        gas_price: Some(
            86624081747,
        ),
        gas: 46258,
        input: Bytes(
            b"\xa2,\xb4e\0\0\0\0\0\0\0\0\0\0\0\0Mt\x1c(\xc4\r\x06(\xe3\xd0\x94S$]\xf7\x7fQ\xfd\xf9]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01",
        ),
        v: 38,
        r: 36074129442019506630029011189037493110736900376526272647848390443457751355846,
        s: 39883350964482382363729019514337022956052712241672243746553175159300450949706,
        transaction_type: Some(
            0,
        ),
        access_list: None,
        max_priority_fee_per_gas: None,
        max_fee_per_gas: None,
        chain_id: None,
    },
)

Running

let bundle = BundleRequest::new()
    .push_transaction(tx)
    .set_simulation_block(block_number)
    .set_block(block_number + 1);

let simulated_bundle = client.inner().simulate_bundle(&bundle).await;

will result in:

`err="rlp: expected input string or byte for *big.Int, decoding into (types.LegacyTx).GasPrice"

Somewhere along the way the GasPrice is wrongly set to 0 or None, I assume. I am not sure how to debug this. I think to the core writer the position in code to check should be obvious? I am a bit new to rust...
I think this is due to EIP1559 changes, which might result in setting the GasPrice to None, as if BaseFee/... is set this would lead to an error if GasPrice has a value as well...

If it helps to have a working example, please tell me.

Error when simulating transaction. header not found

Getting the following error when trying to simulate transaction. I've tried with Geth,Erigon, and Reth. What could cause this?

RelayError(JsonRpcError(JsonRpcError { code: -32000, message: "header not found", data: None })

jsonrpc.rs Error("data did not match any variant of untagged enum ResponseData")

I simulated some random tx from mempool before they were include in a block.
The line client.inner().simulate_bundle(&bundle).await; throwed following errors

tx 0x28c338e677518eb9a3b0ce150a54a787464b1e0ee6407ca9a2cfca3e7f1da08f reverted and some log messages (from SushiSwap Router) "Fail with error 'TransferHelper: TRANSFER_FROM_FAILED'" are inside value field.

RelayError(
    ResponseSerdeJson {
        err: Error("data did not match any variant of untagged enum ResponseData", line: 1, column: 1249),
        text: "{\"jsonrpc\":\"2.0\",\"id\":20,\"result\":{\"bundleGasPrice\":\"1500000000\",\"bundleHash\":\"0xac94fedbf37d864f006c12945e7a50fe9e712ec25a5da833666337bca3fcecf1\",\"coinbaseDiff\":\"86709000000000\",\"ethSentToCoinbase\":\"0\",\"gasFees\":\"86709000000000\",\"results\":[{\"coinbaseDiff\":\"86709000000000\",\"error\":\"execution reverted\",\"ethSentToCoinbase\":\"0\",\"fromAddress\":\"0xb97dC3cd69a7Daf67cF3f11A9CB8BE368Bc46C6f\",\"gasFees\":\"86709000000000\",\"gasPrice\":\"1500000000\",\"gasUsed\":57806,\"revert\":\"\\u0008\\ufffdy\\ufffd\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000 \\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000$TransferHelper: TRANSFER_FROM_FAILED\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\\u0000\",\"toAddress\":\"0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F\",\"txHash\":\"0x28c338e677518eb9a3b0ce150a54a787464b1e0ee6407ca9a2cfca3e7f1da08f\"}],\"stateBlockNumber\":13125885,\"totalGasUsed\":57806}}\n",
    },
)

tx 0x05261313ae0b76dc336dac8e63d66a3b348fca5d36a77418a5a94713d0bd8aa0 reverted (ouf of gas).

RelayError(
    ResponseSerdeJson {
        err: Error("data did not match any variant of untagged enum ResponseData", line: 1, column: 647),
        text: "{\"jsonrpc\":\"2.0\",\"id\":257,\"result\":{\"bundleGasPrice\":\"1500000000\",\"bundleHash\":\"0x9cf150b16c37243d6c3a5b31113e47f1bbe20f8cb3fee40c43263092644269bd\",\"coinbaseDiff\":\"310987500000000\",\"ethSentToCoinbase\":\"0\",\"gasFees\":\"310987500000000\",\"results\":[{\"coinbaseDiff\":\"310987500000000\",\"error\":\"execution reverted\",\"ethSentToCoinbase\":\"0\",\"fromAddress\":\"0x3438ea7671A46A493672595C0E2FB23E4C3aaA66\",\"gasFees\":\"310987500000000\",\"gasPrice\":\"1500000000\",\"gasUsed\":207325,\"toAddress\":\"0x1A2a1c938CE3eC39b6D47113c7955bAa9DD454F2\",\"txHash\":\"0x05261313ae0b76dc336dac8e63d66a3b348fca5d36a77418a5a94713d0bd8aa0\"}],\"stateBlockNumber\":13125898,\"totalGasUsed\":207325}}\n",
    },
)

tx 0x27757cbf58e8eedd881a0d2f4b99a340d689269e74d3bf93690b3f1f35f8546e succeeded, but log messages are inside value field. https://etherscan.io/tx/0x27757cbf58e8eedd881a0d2f4b99a340d689269e74d3bf93690b3f1f35f8546e#eventlog

RelayError(
    ResponseSerdeJson {
        err: Error("data did not match any variant of untagged enum ResponseData", line: 1, column: 951),
        text: "{\"jsonrpc\":\"2.0\",\"id\":662,\"result\":{\"bundleGasPrice\":\"2050000000\",\"bundleHash\":\"0xb14a4c5fba855329ba679d512717e538927b7b21bf67504b3015ad5fbd18af6f\",\"coinbaseDiff\":\"386078550000000\",\"ethSentToCoinbase\":\"0\",\"gasFees\":\"386078550000000\",\"results\":[{\"coinbaseDiff\":\"386078550000000\",\"ethSentToCoinbase\":\"0\",\"fromAddress\":\"0x3D78aeBfEB21286B38E8E158bE77d2990715651a\",\"gasFees\":\"386078550000000\",\"gasPrice\":\"2050000000\",\"gasUsed\":188331,\"toAddress\":\"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D\",\"txHash\":\"0x27757cbf58e8eedd881a0d2f4b99a340d689269e74d3bf93690b3f1f35f8546e\",\"value\":\"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000002037c9eaac64e4519eb0b3c90000000000000000000000000000000000000000000000002fd89477d0ab3cab000000000000000000000000000000000000000000000000000000028e3825cc\"}],\"stateBlockNumber\":13125900,\"totalGasUsed\":188331}}\n",
    },
)

Looks like ethers-flashbots/src/jsonrpc.rs could see some tweaking.

various builders transmission errors

i just wanted to open this to leave some errors i've gotten from some builders using this lib, maybe it could be accounted for

// Deserialization error: EOF while parsing a value at line 1 column 0. Response:
    // "https://rpc.bobthebuilder.xyz",
    
    // Client error: bad signature
    // "https://blockbeelder.com/rpc",

    // "https://builder0x69.io/", //redacted CLOUDFLARE

    // Deserialization error: data did not match any variant of untagged enum ResponseData at line 1 column 39. Response: {"jsonrpc":"2.0","id":1,"result":"nil"}
    // "https://rpc.lokibuilder.xyz"

    // Deserialization error: data did not match any variant of untagged enum ResponseData at line 1 column 102. Response: {"id":1,"jsonrpc":"2.0","result":"0x681dca701bb7499fdfbaad6663cef3e0572d725fc4d80b5b1bdd5132f0818dae"}
    // "https://rpc.tbuilder.xyz"

    // Deserialization error: missing field `id` at line 1 column 110. Response: {"jsonrpc":"2.0","result":{"bundleHash":"0xf1aaf7e76f837b2f226277fffa81e84a44ffae2021669eccb76462439d999c1a"}}
    // "https://rpc.payload.de",

    // Client error: {"id":0,"error":{"code":-32004,"message":"Invalid account ID","data":"auth header cannot be empty"},"jsonrpc":"2.0"}
    // "https://mev.api.blxrbdn.com",

    // Deserialization error: trailing characters at line 2 column 1. Response: {"jsonrpc":"2.0","id":1,"result":null}
    // "https://rpc.lightspeedbuilder.info",
    ```

Error simulating tx with ethers-rs 2.0

Using the latest version 0.13.1 with the latest ethers-rs 2.0.6 compiles fine but trying to simulate a tx results in an error from the flashbots relay:

    source: RelayError(
        ClientError {
            text: "{\"error\":\"unable to decode txs\"}",
        },
    ),

Simplify examples

I think we might be able to simplify the examples in terms of imports and outside dependencies.

Add naive sandwiching example

It could probably go like this:

  1. Get pending transactions
  2. Filter them for transactions that perform a swap by checking the 4bytes
  3. Attempt to parse swap parameters
  4. Construct front and back transactions within parameters
  5. Construct the bundle
  6. Simulate and submit the bundle

To simplify things a bit, we can just bribe the miner using gas prices instead of using coinbase.transfer.

Error: (code: -32000, message: header not found, data: None)

Hi, sir, when I used the following script to simulate a bundle, I got the error : Error: (code: -32000, message: header not found, data: None). This is my Cargo.toml file:

tokio = { version = "1.0.1", features = ["full"] }
# ethers = { git = "https://github.com/gakonst/ethers-rs", features = [ "abigen", "ws", "rustls" ] }
ethers = { version = "2.0.0", features = [ "abigen", "ws", "rustls" ] }
# ethers-flashbots = "0.10.0"
ethers-flashbots = { git = "https://github.com/onbjerg/ethers-flashbots" }

How to slove this? Thanks!

use eyre::Result;
use ethers::core::rand::thread_rng;
use ethers::{
    prelude::*,
    types::transaction::{eip2718::TypedTransaction, eip2930::AccessList},
};
use std::{time::{SystemTime, UNIX_EPOCH}, ops::Add, str::FromStr};
use ethers_flashbots::*;
use std::convert::TryFrom;
use reqwest::Url;
use project::{utils};
use dotenv::dotenv;

#[tokio::main]
async fn main() -> Result<()> {

    dotenv().ok();

    let client = utils::create_websocket_client().await?;
    let provider = utils::get_http_provider()?;
    let bundle_signer = utils::get_bundle_signer()?;
    let wallet1 = utils::get_searcher_wallet()?;
    let wallet2 = utils::get_victim_wallet()?;
    let chain_id = utils::get_chain_id().unwrap();

    // Add signer and Flashbots middleware
    let flashbots_client = SignerMiddleware::new(
        FlashbotsMiddleware::new(
            provider,
            Url::parse("https://relay-goerli.flashbots.net")?,
            bundle_signer,
        ),
        wallet1.clone(),
    );

    let block = client.get_block(BlockId::Number(BlockNumber::Latest)).await?.unwrap();
    let next_base_fee = utils::calculate_next_block_base_fee(block.clone()).unwrap();

    let max_priority_fee_per_gas = U256::from(1000);

    let nonce = client
    .get_transaction_count(wallet1, None)
    .await?;

    let transaction1_request = Eip1559TransactionRequest {
        to: Some(NameOrAddress::Address(wallet2)),
        from: Some(wallet1),
        data: None,
        chain_id: Some(chain_id),
        max_priority_fee_per_gas: Some(max_priority_fee_per_gas),
        max_fee_per_gas: Some(next_base_fee.add(max_priority_fee_per_gas)),
        gas: Some(U256::from(250000)),
        nonce: Some(nonce),
        value: Some(U256::from(1000)),
        access_list: AccessList::default(),
    };

    let transaction2_request = Eip1559TransactionRequest {
        to: Some(NameOrAddress::Address(wallet2)),
        from: Some(wallet1),
        data: None,
        chain_id: Some(chain_id),
        max_priority_fee_per_gas: Some(max_priority_fee_per_gas),
        max_fee_per_gas: Some(next_base_fee.add(max_priority_fee_per_gas)),
        gas: Some(U256::from(250000)),
        nonce: Some(nonce + 1),
        value: Some(U256::from(1000)),
        access_list: AccessList::default(),
    };
   
    // sign the transaction1
    let transaction1_typed = TypedTransaction::Eip1559(transaction1_request);
    let signed_transaction1_sig =
            if let Ok(s) = search_wallet.sign_transaction(&transaction1_typed).await {
                s
            } else {
                return Ok(());
            };
    let signed_transaction1 = transaction1_typed.rlp_signed(&signed_transaction1_sig);

    // sign the transaction2
    let transaction2_typed = TypedTransaction::Eip1559(transaction2_request);
    let signed_transaction2_sig =
            if let Ok(s) = search_wallet.sign_transaction(&transaction2_typed).await {
                s
            } else {
                return Ok(());
            };
    let signed_transaction2 = transaction2_typed.rlp_signed(&signed_transaction2_sig);

    tracing::info!("Signed Transaction!");

    let target = if let Some(b) = block.number {
        b + 1
    } else {
        return Ok(());
    };

    let bundle = BundleRequest::new()
    .push_transaction(signed_transaction1)
    .set_block(target)
    .set_simulation_block(target)
    .set_simulation_timestamp(0);

    // Simulate it
    let simulated_bundle = flashbots_client.inner().simulate_bundle(&bundle).await?;
    println!("Simulated bundle: {:?}", simulated_bundle);

    Ok(())
}

Check for bundle inclusion

Instead of just returning the bundle hash when using send_bundle, we should return a type PendingBundle that acts like ethers' PendingTransaction, just for bundles.

Include signed Transaction from mempool : RelayError(ClientError { text: "{\"error\":\"unable to decode txs\"}" })

Hi and thank you very much for your work. This is working perfectly if i create my owns transactions and include it in a flashbots bundle.

I am having trouble to include someone else transaction in the bundle.

I am getting someone else TX from the network and create a new TransactionRequest like :

// Create a new TransactionRequest using the extracted data
let transaction = TransactionRequest {

        chain_id: Some(chain_id),
        from : Some(from_address),
        gas: Some(gas),
        gas_price : Some(gas_price),
        data: Some(victims_data),
        nonce: Some(nonce_victim),          
        to: Some(to_name_or_address),
        value: Some(value),
        
    }; 

Then i create the signature from the victim's data :

// Create a Signature from v, r, and s
let signature = Signature { v, r, s };

and then i include it with another tx in my bundle:

let bundle = BundleRequest::new()
.push_transaction(transaction .rlp_signed(&signature))
.set_block(block_number + 1)
.set_simulation_block(block_number)
.set_simulation_timestamp(0);

However, i got the error -> RelayError(ClientError { text: "{"error":"unable to decode txs"}" }) when i try to simulate the bundle.

Do you know where it can come from? Thank you very much for your help !

Can not create FlashbotsMiddleware

I can't seem to find out why there is a trait issue when following the example code:

the trait bound `Wallet<SigningKey>: ethers_signers::Signer` is not satisfied
let provider = Provider::<Http>::try_from(remote)?;
let bundle_signer = LocalWallet::new(&mut thread_rng());
let middleware = FlashbotsMiddleware::new(
    provider.clone(),
    Url::parse("https://relay.flashbots.net")?,
    bundle_signer,
);
ethers = { git = "https://github.com/gakonst/ethers-rs" }
ethers-flashbots = "0.8.1"

Misleading bundle inclusion

// Check if the bundle transactions are present in the block
// Since a bundle cannot be divided, we only need to check
// if the first transaction was included.
//
// Note: The indexed access is safe, since empty bundles
// (i.e. bundles with no transactions) cannot be submitted.

I think this logic of checking only the first transaction was included, is a bit flawed, because there may have been a competing bundle that landed in the same target block with the same first transaction that was being backrun.

Thus it would think the submitted bundle was included, while it was actually a competing bundle with the same specs was the one that got included

Calling "flashbots_getBundleStatsV2" sometimes fails

Ty for updating the new endpoints @onbjerg!

Just did some testing on Goerli and it works fine most of the time, it does seem tough that sometimes the JSON response from flashbots is lacking some fields resulting in a parsing error:

    Error {
        msg: "flashbots.get_bundle_stats(<hash>, <block>)",
        source: RelayError(
            ResponseSerdeJson {
                err: Error("data did not match any variant of untagged enum ResponseData", line: 1, column: 156),
                text: "{\"id\":3,\"result\":{\"isSimulated\":true,\"isHighPriority\":true,\"simulatedAt\":\"2022-12-24T17:18:52.689Z\",\"receivedAt\":\"2022-12-24T17:18:52.68Z\"},\"jsonrpc\":\"2.0\"}",
            },
        ),
    },

Other times the response is as expected:

Good response example
    BundleStats {
        is_high_priority: true,
        is_simulated: true,
        simulated_at: Some(
            2022-12-24T17:20:15.387Z,
        ),
        received_at: Some(
            2022-12-24T17:20:15.380Z,
        ),
        considered_by_builders_at: [
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:30.707Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:31.207Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:31.707Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:32.207Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:32.707Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:33.211Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:33.712Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:34.207Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:34.707Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:30.964Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:31.464Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:31.963Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:32.463Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:32.964Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:33.463Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:34.464Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:35.464Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:35.963Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:35.207Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:35.707Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:36.207Z,
                ),
            },
        ],
        sealed_by_builders_at: [
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:30.828Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:31.254Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:31.755Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:32.289Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:32.756Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:33.292Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:33.876Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:34.257Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:34.757Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:31.031Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:31.500Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:32.002Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:32.506Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:33.011Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:33.505Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:34.502Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:35.510Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xb67a5148a03229926e34b190af81a82a81c4df66831c98c03a139778418dd09a3b542ced0022620d19f35781ece6dc36),
                timestamp: Some(
                    2022-12-24T17:20:36.007Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:35.260Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:35.760Z,
                ),
            },
            BuilderEntry {
                pubkey: Bytes(0xa1dead01e65f0a0eee7b5170223f20c8f0cbf122eac3324d61afbdb33a8885ff8cab2ef514ac2c7698ae0d6289ef27fc),
                timestamp: Some(
                    2022-12-24T17:20:36.258Z,
                ),
            },
        ],
    },

It seems that the fields considered_by_builders_at and sealed_by_builders_at are not always present in the response causing the deserialization error.

New Release

With #45 merged, can we please cut a new release to avoid transitive dependency issues with ethers v1.0.2? ๐Ÿ™

Nonce management strategies

Wondering if this is something we can build into this lib and also ignite some discussion around the same.

What is the nonce management strategy that you are using with flashbots? When I think about it there are some challenges:

  1. If you discover multiple opportunities / bundles to send at same block, if you set nonces x, x + 1, if x bundle doesn't get included because a conflicting bundle outbid, then x + 1 won't be a valid bundle because correct nonce for next tx to land on chain would be x.
  2. If your bundle don't gets included you have to either keep retrying(but only if the bundle is still valid, so maybe there even needs some way to check if the opportunity still exists), again the nonce problem remains, more bundles may have landed in your queue and you would need their nonces to be correct and land in same order.

I think the simple fix here is:

  1. Use multiple EOAs, so if you have 10 EOAs, you can at max have 10 bundles you can keep trying, so a queue with number of EOAs equal to servers and everything more than that falls in the queue, which maybe limiting because the ones in queue may be non-competitive and could've landed in first try, etc. Multiple EOAs are not ideal because now you'd need to have more complicated RBAC auth on chain.

The middleware for the above alternative would probably queue bundles whenever send_transaction or send_bundle gets called? Watch for blocks and every new block, check if any previously sent block got confirmed and remove them from queue if they did, check if the tx is valid(maybe closures? or just drop this for now), set relevant nonce and sign them with nth EOA and submit all of the bundles. Repeat.

Errors with the advanced example

When I run the advanced example with a real funded wallet,
the call to simulate (client.inner().simulate_bundle(&bundle).await?;) returns Error: Some parameters were missing.

The first thing that simulate_bundle runs is

bundle
            .block()
            .and(bundle.simulation_block())
            .and(bundle.simulation_timestamp())
            .ok_or(FlashbotsMiddlewareError::MissingParameters)?;

so I added a simulation_block and simulation_timestamp to the bundle:

    let bundle = BundleRequest::new()
        .push_transaction(tx.rlp_signed(client.signer().chain_id(), &signature))
        .set_block(block_number + 1)
        // these next 2 lines are new
        .set_simulation_block(block_number + 1)
        .set_simulation_timestamp(0);

And testing on goerli (https://relay-goerli.flashbots.net) I still get an error which I don't understand:

Error: (code: -32000, message: header not found, data: None)

Modernize a bit

CI

  • Use Swatinem/rust-cache
  • Use minimal profile (with rustfmt and clippy)

eth_estimateGasBundle

Hi,

I think it could be useful to include a method wrapping mev-geth's eth_estimateGasBundle endoint.

Thanks!

Compilation error with 0.13.0

Hi

I get the following error when I compile ethers-flashbot 0.13.0 coming with the ethers-signers v2.0.0 package.

15 | ecdsa::{recoverable::Signature as RecoverableSignature, signature::DigestSigner},
| ^^^^^^^^^^^ could not find recoverable in ecdsa

Note that ethers compile on its own without any issue.

Thanks!

Add changelog

Should retroactively add changes too for the different version

Transaction validation

Currently there is nothing preventing anyone from adding arbitrary invalid bytes to their bundle, even by mistake. We should try to decode the RLP encoded transactions and make sure they have all the necessary parameters (nonce, gas_price, gas, to, value, input, v, r, s).

Simulation problem

Hi everyone,

I was performing test on the Goerli testnet and everything was going fine. I was able to create different transactions (TypedTransaction) using Eip1559TransactionRequest and include them in a bundle, simulate it and send it. Everything was going fine.

Now here is the problem, i decided to go live on the mainnet, i use my own node and when i simulate the transaction the gas price simulated of the tx inside the bundle is not the same as the one i put during the creation of the transaction itself. The problem is only when i am on the mainnet and even if i use a public node i have the same problem.

Has anyone already experienced this? Could it be a serialization problem?

Thank you in advance for your help and have a good day !

calling flashbots_getUserStats fails

Calling get_user_stats fails with:

        RelayError(
            RequestError(
                reqwest::Error {
                    kind: Status(
                        500,
                    ),
                    url: Url {
                        scheme: "https",
                        cannot_be_a_base: false,
                        username: "",
                        password: None,
                        host: Some(
                            Domain(
                                "relay-goerli.flashbots.net",
                            ),
                        ),
                        port: None,
                        path: "/",
                        query: None,
                        fragment: None,
                    },
                },
            ),
        )

Might be related to the failure of flashbots_getBundleStats I reported in flashbots/rpc-endpoint#108, specifically this comment.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.