Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: chain specific 1559 fee estimation #3368

Merged
merged 3 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

18 changes: 15 additions & 3 deletions cli/src/cmd/forge/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use ethers::{
types::{transaction::eip2718::TypedTransaction, Chain},
};
use eyre::Context;
use foundry_common::{abi::parse_tokens, compile, try_get_http_provider};
use foundry_common::{abi::parse_tokens, compile, estimate_eip1559_fees, try_get_http_provider};
use rustc_hex::ToHex;
use serde_json::json;
use std::{path::PathBuf, sync::Arc};
Expand Down Expand Up @@ -192,9 +192,21 @@ impl CreateArgs {
// will fail and create will fail
provider.fill_transaction(&mut deployer.tx, None).await?;

// the max
let mut priority_fee = self.tx.priority_gas_price;

// set gas price if specified
if let Some(gas_price) = self.tx.gas_price {
deployer.tx.set_gas_price(gas_price);
} else if !is_legacy {
// estimate EIP1559 fees
let (max_fee, max_priority_fee) = estimate_eip1559_fees(&provider, Some(chain))
.await
.wrap_err("Failed to estimate EIP1559 fees")?;
deployer.tx.set_gas_price(max_fee);
if priority_fee.is_none() {
priority_fee = Some(max_priority_fee);
}
}

// set gas limit if specified
Expand All @@ -208,9 +220,9 @@ impl CreateArgs {
}

// set priority fee if specified
if let Some(priority_fee) = self.tx.priority_gas_price {
if let Some(priority_fee) = priority_fee {
if is_legacy {
panic!("there is no priority fee for legacy txs");
eyre::bail!("there is no priority fee for legacy txs");
}
deployer.tx = match deployer.tx {
TypedTransaction::Eip1559(eip1559_tx_request) => TypedTransaction::Eip1559(
Expand Down
8 changes: 6 additions & 2 deletions cli/src/cmd/forge/script/broadcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use ethers::{
utils::format_units,
};
use eyre::{ContextCompat, WrapErr};
use foundry_common::{try_get_http_provider, RetryProvider};
use foundry_common::{estimate_eip1559_fees, try_get_http_provider, RetryProvider};
use foundry_config::Chain;
use futures::StreamExt;
use indicatif::{ProgressBar, ProgressStyle};
Expand Down Expand Up @@ -59,7 +59,11 @@ impl ScriptArgs {
(provider.get_gas_price().await.ok(), None)
}
TypedTransaction::Eip1559(_) => {
(None, provider.estimate_eip1559_fees(None).await.ok())
let fees = estimate_eip1559_fees(&provider, Some(chain))
.await
.wrap_err("Failed to estimate EIP1559 fees")?;

(None, Some(fees))
}
}
};
Expand Down
5 changes: 5 additions & 0 deletions cli/tests/it/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ forgetest!(can_create_oracle_on_goerli, |prj: TestProject, cmd: TestCommand| {
create_on_chain(EnvExternalities::goerli(), prj, cmd, setup_oracle);
});

// tests `forge` create on mumbai if correct env vars are set
forgetest!(can_create_oracle_on_mumbai, |prj: TestProject, cmd: TestCommand| {
create_on_chain(EnvExternalities::mumbai(), prj, cmd, setup_oracle);
});

// tests that we can deploy the template contract
forgetest_async!(
#[serial_test::serial]
Expand Down
10 changes: 10 additions & 0 deletions cli/tests/it/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ impl EnvExternalities {
})
}

pub fn mumbai() -> Option<Self> {
Some(Self {
chain: Chain::PolygonMumbai,
rpc: network_rpc_key("mumbai")?,
pk: network_private_key("mumbai")?,
etherscan: etherscan_key(Chain::PolygonMumbai)?,
verifier: "etherscan".to_string(),
})
}

/// Returns the arguments required to deploy the contract
pub fn create_args(&self) -> Vec<String> {
vec![
Expand Down
1 change: 1 addition & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ foundry-config = { path = "../config" }
ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
ethers-providers = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
ethers-middleware = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["ethers-solc"] }

# io
Expand Down
35 changes: 34 additions & 1 deletion common/src/provider.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Commonly used helpers to construct `Provider`s

use crate::{ALCHEMY_FREE_TIER_CUPS, REQUEST_TIMEOUT};
use ethers_core::types::Chain;
use ethers_core::types::{Chain, U256};
use ethers_middleware::gas_oracle::{GasCategory, GasOracle, Polygon};
use ethers_providers::{
is_local_endpoint, Http, HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient,
RetryClientBuilder, DEFAULT_LOCAL_POLL_INTERVAL,
Expand Down Expand Up @@ -199,6 +200,38 @@ impl<'a> From<Cow<'a, str>> for ProviderBuilder {
}
}

/// Estimates EIP1559 fees depending on the chain
///
/// Uses custom gas oracles for
/// - polygon
///
/// Fallback is the default [`Provider::estimate_eip1559_fees`] implementation
pub async fn estimate_eip1559_fees<M: Middleware>(
provider: &M,
chain: Option<u64>,
) -> eyre::Result<(U256, U256)>
where
M::Error: 'static,
{
let chain = if let Some(chain) = chain {
chain
} else {
provider.get_chainid().await.wrap_err("Failed to get chain id")?.as_u64()
};

if let Ok(chain) = Chain::try_from(chain) {
// handle chains that deviate from `eth_feeHistory` and have their own oracle
match chain {
Chain::Polygon | Chain::PolygonMumbai => {
let estimator = Polygon::new(chain)?.category(GasCategory::Standard);
return Ok(estimator.estimate_eip1559_fees().await?)
}
_ => {}
}
}
provider.estimate_eip1559_fees(None).await.wrap_err("Failed fetch EIP1559 fees")
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down