diff --git a/main/src/activate.rs b/main/src/activate.rs index 8526d8f..ccb59e5 100644 --- a/main/src/activate.rs +++ b/main/src/activate.rs @@ -1,24 +1,22 @@ // Copyright 2023-2024, Offchain Labs, Inc. // For licensing, see https://github.com/OffchainLabs/cargo-stylus/blob/stylus/licenses/COPYRIGHT.md +use crate::check::check_activate; +use crate::constants::ARB_WASM_H160; +use crate::macros::greyln; use crate::util::color::{Color, DebugColor}; use crate::util::sys; +use crate::ActivateConfig; use alloy_primitives::Address; use alloy_sol_macro::sol; use alloy_sol_types::SolCall; use ethers::middleware::{Middleware, SignerMiddleware}; use ethers::signers::Signer; use ethers::types::transaction::eip2718::TypedTransaction; -use ethers::types::{Eip1559TransactionRequest, U256}; +use ethers::types::Eip1559TransactionRequest; use ethers::utils::format_units; use eyre::{bail, Context, Result}; -use crate::check::check_activate; -use crate::constants::ARB_WASM_H160; -use crate::macros::greyln; - -use crate::ActivateConfig; - sol! { interface ArbWasm { function activateProgram(address program) @@ -41,25 +39,14 @@ pub async fn activate_contract(cfg: &ActivateConfig) -> Result<()> { let client = SignerMiddleware::new(provider.clone(), wallet); let code = client.get_code(cfg.address, None).await?; - let data_fee = check_activate(code, cfg.address, &provider).await?; - let mut data_fee = alloy_ethers_typecast::alloy_u256_to_ethers(data_fee); - - greyln!( - "obtained estimated activation data fee {}", - format_units(data_fee, "ether")?.debug_lavender() - ); - greyln!( - "bumping estimated activation data fee by {}%", - cfg.data_fee_bump_percent.debug_lavender() - ); - data_fee = bump_data_fee(data_fee, cfg.data_fee_bump_percent); + let data_fee = check_activate(code, cfg.address, &cfg.data_fee, &provider).await?; let contract: Address = cfg.address.to_fixed_bytes().into(); let data = ArbWasm::activateProgramCall { program: contract }.abi_encode(); let tx = Eip1559TransactionRequest::new() .from(client.address()) .to(*ARB_WASM_H160) - .value(data_fee) + .value(alloy_ethers_typecast::alloy_u256_to_ethers(data_fee)) .data(data); let tx = TypedTransaction::Eip1559(tx); if cfg.estimate_gas { @@ -96,8 +83,3 @@ pub async fn activate_contract(cfg: &ActivateConfig) -> Result<()> { } Ok(()) } - -fn bump_data_fee(fee: U256, pct: u64) -> U256 { - let num = 100 + pct; - fee * U256::from(num) / U256::from(100) -} diff --git a/main/src/check.rs b/main/src/check.rs index 5c31ea6..767153f 100644 --- a/main/src/check.rs +++ b/main/src/check.rs @@ -1,13 +1,13 @@ // Copyright 2023-2024, Offchain Labs, Inc. // For licensing, see https://github.com/OffchainLabs/cargo-stylus/blob/main/licenses/COPYRIGHT.md -use crate::util::{color::Color, sys, text}; use crate::{ check::ArbWasm::ArbWasmErrors, constants::{ARB_WASM_H160, ONE_ETH, TOOLCHAIN_FILE_NAME}, macros::*, project::{self, extract_toolchain_channel, BuildConfig}, - CheckConfig, + util::{color::Color, sys, text}, + CheckConfig, DataFeeOpts, }; use alloy_primitives::{Address, B256, U256}; use alloy_sol_macro::sol; @@ -87,9 +87,7 @@ pub async fn check(cfg: &CheckConfig) -> Result { } let address = cfg.contract_address.unwrap_or(H160::random()); - let fee = check_activate(code.clone().into(), address, &provider).await?; - let visual_fee = format_data_fee(fee).unwrap_or("???".red()); - greyln!("wasm data fee: {visual_fee} ETH"); + let fee = check_activate(code.clone().into(), address, &cfg.data_fee, &provider).await?; Ok(ContractCheck::Ready { code, fee }) } @@ -112,7 +110,7 @@ impl ContractCheck { pub fn suggest_fee(&self) -> U256 { match self { Self::Active { .. } => U256::default(), - Self::Ready { fee, .. } => fee * U256::from(120) / U256::from(100), + Self::Ready { fee, .. } => *fee, } } } @@ -148,17 +146,19 @@ pub fn format_file_size(len: usize, mid: u64, max: u64) -> String { } /// Pretty-prints a data fee. -fn format_data_fee(fee: U256) -> Result { - let fee: u64 = (fee / U256::from(1e9)).try_into()?; +fn format_data_fee(fee: U256) -> String { + let Ok(fee): Result = (fee / U256::from(1e9)).try_into() else { + return ("???").red(); + }; let fee: f64 = fee as f64 / 1e9; - let text = format!("{fee:.6}"); - Ok(if fee <= 5e14 { + let text = format!("{fee:.6} ETH"); + if fee <= 5e14 { text.mint() } else if fee <= 5e15 { text.yellow() } else { text.pink() - }) + } } pub struct EthCallError { @@ -247,7 +247,12 @@ Perhaps the Arbitrum node for the endpoint you are connecting to has not yet upg } /// Checks contract activation, returning the data fee. -pub async fn check_activate(code: Bytes, address: H160, provider: &Provider) -> Result { +pub async fn check_activate( + code: Bytes, + address: H160, + opts: &DataFeeOpts, + provider: &Provider, +) -> Result { let contract = Address::from(address.to_fixed_bytes()); let data = ArbWasm::activateProgramCall { program: contract }.abi_encode(); let tx = Eip1559TransactionRequest::new() @@ -256,8 +261,17 @@ pub async fn check_activate(code: Bytes, address: H160, provider: &Provider Result<()> { return Ok(()); } - if cfg.no_activate { - mintln!( - r#"NOTE: You must activate the stylus contract before calling it. To do so, we recommend running: -cargo stylus activate --address {}"#, - hex::encode(contract_addr) - ); - return Ok(()); - } - match contract { ContractCheck::Ready { .. } => { - cfg.activate(sender, contract_addr, data_fee, &client) - .await? + if cfg.no_activate { + mintln!( + r#"NOTE: You must activate the stylus contract before calling it. To do so, we recommend running: +cargo stylus activate --address {}"#, + hex::encode(contract_addr) + ); + } else { + cfg.activate(sender, contract_addr, data_fee, &client) + .await? + } } ContractCheck::Active { .. } => greyln!("wasm already activated!"), } diff --git a/main/src/main.rs b/main/src/main.rs index 8e9bc11..846ce97 100644 --- a/main/src/main.rs +++ b/main/src/main.rs @@ -181,15 +181,14 @@ pub struct CacheSuggestionsConfig { pub struct ActivateConfig { #[command(flatten)] common_cfg: CommonConfig, + #[command(flatten)] + data_fee: DataFeeOpts, /// Wallet source to use. #[command(flatten)] auth: AuthOpts, /// Deployed Stylus contract address to activate. #[arg(long)] address: H160, - /// Percent to bump the estimated activation data fee by. Default of 20% - #[arg(long, default_value = "20")] - data_fee_bump_percent: u64, /// Whether or not to just estimate gas without sending a tx. #[arg(long)] estimate_gas: bool, @@ -199,6 +198,8 @@ pub struct ActivateConfig { pub struct CheckConfig { #[command(flatten)] common_cfg: CommonConfig, + #[command(flatten)] + data_fee: DataFeeOpts, /// The WASM to check (defaults to any found in the current directory). #[arg(long)] wasm_file: Option, @@ -314,6 +315,13 @@ pub struct SimulateArgs { use_native_tracer: bool, } +#[derive(Clone, Debug, Args)] +struct DataFeeOpts { + /// Percent to bump the estimated activation data fee by. + #[arg(long, default_value = "20")] + data_fee_bump_percent: u64, +} + #[derive(Clone, Debug, Args)] #[clap(group(ArgGroup::new("key").required(true).args(&["private_key_path", "private_key", "keystore_path"])))] struct AuthOpts { diff --git a/main/src/verify.rs b/main/src/verify.rs index c65223b..3ba5f68 100644 --- a/main/src/verify.rs +++ b/main/src/verify.rs @@ -18,7 +18,7 @@ use crate::{ constants::TOOLCHAIN_FILE_NAME, deploy::{self, extract_compressed_wasm, extract_contract_evm_deployment_prelude}, project::{self, extract_toolchain_channel}, - CheckConfig, VerifyConfig, + CheckConfig, DataFeeOpts, VerifyConfig, }; #[derive(Debug, Deserialize, Serialize)] @@ -52,6 +52,9 @@ pub async fn verify(cfg: VerifyConfig) -> eyre::Result<()> { } let check_cfg = CheckConfig { common_cfg: cfg.common_cfg.clone(), + data_fee: DataFeeOpts { + data_fee_bump_percent: 20, + }, wasm_file: None, contract_address: None, };