Skip to content

Commit

Permalink
feat(provider): modify provider traits for new types, impl alloy prov…
Browse files Browse the repository at this point in the history
…ider
  • Loading branch information
dancoombs committed Sep 19, 2024
1 parent 819403f commit a68e68a
Show file tree
Hide file tree
Showing 22 changed files with 1,895 additions and 1,722 deletions.
44 changes: 37 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ alloy-sol-types = "0.8.3"
alloy-consensus = "0.3.3"
alloy-contract = "0.3.3"
alloy-json-rpc = "0.3.3"
alloy-provider = "0.3.3"
alloy-provider = { version = "0.3.3", default-features = false }
alloy-rpc-client = "0.3.3"
alloy-rpc-types-eth = "0.3.3"
alloy-rpc-types-trace = "0.3.3"
Expand Down Expand Up @@ -52,7 +52,7 @@ rand = "0.8.5"
reqwest = { version = "0.12.7", default-features = false, features = ["rustls-tls"] }
rustls = "0.23.12"
thiserror = "1.0.63"
tokio = { version = "1.39.3", default-features = false }
tokio = { version = "1.39.3", default-features = false, features = ["rt", "sync", "time"]}
tokio-util = "0.7.11"
tonic = "0.12.2"
tonic-build = "0.12.2"
Expand Down
20 changes: 13 additions & 7 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,26 @@ repository.workspace = true
publish = false

[dependencies]
rundler-contracts = { path = "../contracts" }
rundler-types = { path = "../types" }
rundler-utils = { path = "../utils" }

alloy-consensus.workspace = true
alloy-contract.workspace = true
alloy-json-rpc.workspace = true
alloy-primitives = { workspace = true, features = ["rand"] }
alloy-provider = { workspace = true, features = ["debug-api", "hyper"] }
alloy-rlp.workspace = true
alloy-rpc-types-eth.workspace = true
alloy-rpc-types-trace.workspace = true
alloy-sol-types.workspace = true
alloy-transport.workspace = true

anyhow.workspace = true
async-trait.workspace = true
auto_impl = "1.2.0"
ethers.workspace = true
metrics.workspace = true
reqwest.workspace = true
serde.workspace = true
tokio.workspace = true
auto_impl.workspace = true
thiserror.workspace = true
tracing.workspace = true
parse-display.workspace = true

mockall = {workspace = true, optional = true }

Expand Down
55 changes: 55 additions & 0 deletions crates/provider/src/alloy/entry_point/arbitrum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// This file is part of Rundler.
//
// Rundler is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later version.
//
// Rundler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Rundler.
// If not, see https://www.gnu.org/licenses/.

use alloy_primitives::{Address, Bytes};
use alloy_provider::Provider as AlloyProvider;
use alloy_sol_types::sol;
use alloy_transport::Transport;

use crate::ProviderResult;

// From https://github.com/OffchainLabs/nitro-contracts/blob/fbbcef09c95f69decabaced3da683f987902f3e2/src/node-interface/NodeInterface.sol#L112
sol! {
#[sol(rpc)]
interface NodeInterface {
function gasEstimateL1Component(
address to,
bool contractCreation,
bytes calldata data
)
external
payable
returns (
uint64 gasEstimateForL1,
uint256 baseFee,
uint256 l1BaseFeeEstimate
);
}
}

pub(crate) async fn estimate_l1_gas<AP: AlloyProvider<T>, T: Transport + Clone>(
provider: AP,
oracle_address: Address,
to_address: Address,
data: Bytes,
) -> ProviderResult<u128> {
let inst = NodeInterface::NodeInterfaceInstance::new(oracle_address, provider);

// assume contract creation
let ret = inst
.gasEstimateL1Component(to_address, true, data)
.call()
.await?;

Ok(ret.gasEstimateForL1 as u128)
}
110 changes: 110 additions & 0 deletions crates/provider/src/alloy/entry_point/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// This file is part of Rundler.
//
// Rundler is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later version.
//
// Rundler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Rundler.
// If not, see https://www.gnu.org/licenses/.

use alloy_consensus::{transaction::SignableTransaction, TxEnvelope, TypedTransaction};
use alloy_primitives::{address, Address, Bytes, Parity, Signature, U256};
use alloy_provider::Provider as AlloyProvider;
use alloy_rlp::Encodable;
use alloy_rpc_types_eth::TransactionRequest;
use alloy_transport::Transport;
use rundler_types::chain::{ChainSpec, L1GasOracleContractType};

use crate::ProviderResult;

pub(crate) mod v0_6;
pub(crate) mod v0_7;

mod arbitrum;
mod optimism;

#[derive(Debug, Default)]
enum L1GasOracle {
ArbitrumNitro(Address),
OptimismBedrock(Address),
#[default]
None,
}

impl L1GasOracle {
fn new(chain_spec: &ChainSpec) -> L1GasOracle {
match chain_spec.l1_gas_oracle_contract_type {
L1GasOracleContractType::ArbitrumNitro => {
L1GasOracle::ArbitrumNitro(chain_spec.l1_gas_oracle_contract_address)
}
L1GasOracleContractType::OptimismBedrock => {
L1GasOracle::OptimismBedrock(chain_spec.l1_gas_oracle_contract_address)
}
L1GasOracleContractType::None => L1GasOracle::None,
}
}

async fn estimate_l1_gas<AP: AlloyProvider<T>, T: Transport + Clone>(
&self,
provider: AP,
to_address: Address,
data: Bytes,
gas_price: u128,
) -> ProviderResult<u128> {
match self {
L1GasOracle::ArbitrumNitro(oracle_address) => {
arbitrum::estimate_l1_gas(provider, *oracle_address, to_address, data).await
}
L1GasOracle::OptimismBedrock(oracle_address) => {
optimism::estimate_l1_gas(provider, *oracle_address, data, gas_price).await
}
L1GasOracle::None => Ok(0),
}
}
}

fn max_bundle_transaction_data(to_address: Address, data: Bytes, gas_price: u128) -> Bytes {
// Fill in max values for unknown or varying fields
let gas_price_ceil = gas_price.next_power_of_two() - 1; // max out bits of gas price, assume same power of 2
let gas_limit = 0xffffffff; // 4 bytes
let nonce = 0xffffffff; // 4 bytes
let chain_id = 0xffffffff; // 4 bytes

let tx = TransactionRequest::default()
.from(address!("ffffffffffffffffffffffffffffffffffffffff"))
.to(to_address)
.gas_limit(gas_limit)
.max_priority_fee_per_gas(gas_price_ceil)
.max_fee_per_gas(gas_price_ceil)
.value(U256::ZERO)
.input(data.into())
.nonce(nonce);

// these conversions should not fail.
let ty = tx.build_typed_tx().unwrap();
let mut tx_1559 = match ty {
TypedTransaction::Eip1559(tx) => tx,
_ => {
panic!("transaction is not eip1559");
}
};

tx_1559.set_chain_id(chain_id);

// use a max signature
let tx_envelope: TxEnvelope = tx_1559
.into_signed(Signature::new(
U256::MAX,
U256::MAX,
Parity::Eip155(u64::MAX),
))
.into();
let mut encoded = vec![];
tx_envelope.encode(&mut encoded);

encoded.into()
}
47 changes: 47 additions & 0 deletions crates/provider/src/alloy/entry_point/optimism.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// This file is part of Rundler.
//
// Rundler is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later version.
//
// Rundler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Rundler.
// If not, see https://www.gnu.org/licenses/.

use alloy_primitives::{ruint::UintTryTo, Address, Bytes};
use alloy_provider::Provider as AlloyProvider;
use alloy_sol_types::sol;
use alloy_transport::Transport;
use anyhow::Context;

use crate::ProviderResult;

// From https://github.com/ethereum-optimism/optimism/blob/f93f9f40adcd448168c6ea27820aeee5da65fcbd/packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L54
sol! {
#[sol(rpc)]
interface GasPriceOracle {
function getL1Fee(bytes memory _data) external view returns (uint256);
}
}

pub(crate) async fn estimate_l1_gas<AP: AlloyProvider<T>, T: Transport + Clone>(
provider: AP,
oracle_address: Address,
data: Bytes,
gas_price: u128,
) -> ProviderResult<u128> {
let oracle = GasPriceOracle::GasPriceOracleInstance::new(oracle_address, provider);

let l1_fee: u128 = oracle
.getL1Fee(data)
.call()
.await?
._0
.uint_try_to()
.context("failed to convert L1 fee to u128")?;

Ok(l1_fee.checked_div(gas_price).unwrap_or(u128::MAX))
}
Loading

0 comments on commit a68e68a

Please sign in to comment.