Skip to content

Commit

Permalink
refactor: similar code in cast send and cast mktx
Browse files Browse the repository at this point in the history
  • Loading branch information
ay committed Feb 8, 2024
1 parent 0e10eb1 commit 55d9f1a
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 92 deletions.
47 changes: 5 additions & 42 deletions crates/cast/bin/cmd/mktx.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cast::TxBuilder;
use crate::tx;
use clap::Parser;
use ethers_core::types::NameOrAddress;
use ethers_middleware::MiddlewareBuilder;
Expand Down Expand Up @@ -75,11 +75,6 @@ impl MakeTxArgs {
None
};

// ensure mandatory fields are provided
if code.is_none() && to.is_none() {
eyre::bail!("Must specify a recipient address or contract code to deploy");
}

let config = Config::from(&eth);
let provider = utils::get_provider(&config)?;
let chain = utils::get_chain(config.chain, &provider).await?;
Expand All @@ -89,49 +84,17 @@ impl MakeTxArgs {
let signer = eth.wallet.signer(chain.id()).await?;
let from = signer.address();

// prevent misconfigured hwlib from sending a transaction that defies
// user-specified --from
if let Some(specified_from) = eth.wallet.from {
if specified_from != from.to_alloy() {
eyre::bail!(
"\
The specified sender via CLI/env vars does not match the sender configured via
the hardware wallet's HD Path.
Please use the `--hd-path <PATH>` parameter to specify the BIP32 Path which
corresponds to the sender, or let foundry automatically detect it by not specifying any sender address."
)
}
}
tx::validate_from_address(eth.wallet.from, from.to_alloy())?;
tx::validate_to_address(&code, &to)?;

if resend {
tx.nonce = Some(provider.get_transaction_count(from, None).await?.to_alloy());
}

let provider = provider.with_signer(signer);

let params = sig.as_deref().map(|sig| (sig, args));
let mut builder = TxBuilder::new(&provider, from, to, chain, tx.legacy).await?;
builder
.etherscan_api_key(api_key)
.gas(tx.gas_limit)
.gas_price(tx.gas_price)
.priority_gas_price(tx.priority_gas_price)
.value(tx.value)
.nonce(tx.nonce);

if let Some(code) = code {
let mut data = hex::decode(code)?;

if let Some((sig, args)) = params {
let (mut sigdata, _) = builder.create_args(sig, args).await?;
data.append(&mut sigdata);
}

builder.set_data(data);
} else {
builder.args(params).await?;
}
let (mut tx, _) = builder.build();
let (mut tx, _) =
tx::build_tx(&provider, from, to, code, sig, args, tx, chain, api_key).await?;

// Fill nonce, gas limit, gas price, and max priority fee per gas if needed
provider.fill_transaction(&mut tx, None).await?;
Expand Down
62 changes: 14 additions & 48 deletions crates/cast/bin/cmd/send.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use cast::{Cast, TxBuilder};
use crate::tx;
use cast::Cast;
use clap::Parser;
use ethers_core::types::NameOrAddress;
use ethers_middleware::MiddlewareBuilder;
Expand Down Expand Up @@ -82,7 +83,7 @@ impl SendTxArgs {
let SendTxArgs {
eth,
to,
sig,
mut sig,
cast_async,
mut args,
mut tx,
Expand All @@ -93,24 +94,20 @@ impl SendTxArgs {
unlocked,
} = self;

let mut sig = sig.unwrap_or_default();
let code = if let Some(SendTxSubcommands::Create {
code,
sig: constructor_sig,
args: constructor_args,
}) = command
{
sig = constructor_sig.unwrap_or_default();
sig = constructor_sig;
args = constructor_args;
Some(code)
} else {
None
};

// ensure mandatory fields are provided
if code.is_none() && to.is_none() {
eyre::bail!("Must specify a recipient address or contract code to deploy");
}
tx::validate_to_address(&code, &to)?;

let config = Config::from(&eth);
let provider = utils::get_provider(&config)?;
Expand Down Expand Up @@ -155,7 +152,8 @@ impl SendTxArgs {
config.sender.to_ethers(),
to,
code,
(sig, args),
sig,
args,
tx,
chain,
api_key,
Expand All @@ -173,19 +171,7 @@ impl SendTxArgs {
let signer = eth.wallet.signer(chain.id()).await?;
let from = signer.address();

// prevent misconfigured hwlib from sending a transaction that defies
// user-specified --from
if let Some(specified_from) = eth.wallet.from {
if specified_from != from.to_alloy() {
eyre::bail!(
"\
The specified sender via CLI/env vars does not match the sender configured via
the hardware wallet's HD Path.
Please use the `--hd-path <PATH>` parameter to specify the BIP32 Path which
corresponds to the sender, or let foundry automatically detect it by not specifying any sender address."
)
}
}
tx::validate_from_address(eth.wallet.from, from.to_alloy())?;

if resend {
tx.nonce = Some(provider.get_transaction_count(from, None).await?.to_alloy());
Expand All @@ -198,7 +184,8 @@ corresponds to the sender, or let foundry automatically detect it by not specify
from,
to,
code,
(sig, args),
sig,
args,
tx,
chain,
api_key,
Expand All @@ -217,7 +204,8 @@ async fn cast_send<M: Middleware, F: Into<NameOrAddress>, T: Into<NameOrAddress>
from: F,
to: Option<T>,
code: Option<String>,
args: (String, Vec<String>),
sig: Option<String>,
args: Vec<String>,
tx: TransactionOpts,
chain: Chain,
etherscan_api_key: Option<String>,
Expand All @@ -228,30 +216,8 @@ async fn cast_send<M: Middleware, F: Into<NameOrAddress>, T: Into<NameOrAddress>
where
M::Error: 'static,
{
let (sig, params) = args;
let params = if !sig.is_empty() { Some((&sig[..], params)) } else { None };
let mut builder = TxBuilder::new(&provider, from, to, chain, tx.legacy).await?;
builder
.etherscan_api_key(etherscan_api_key)
.gas(tx.gas_limit)
.gas_price(tx.gas_price)
.priority_gas_price(tx.priority_gas_price)
.value(tx.value)
.nonce(tx.nonce);

if let Some(code) = code {
let mut data = hex::decode(code)?;

if let Some((sig, args)) = params {
let (mut sigdata, _) = builder.create_args(sig, args).await?;
data.append(&mut sigdata);
}

builder.set_data(data);
} else {
builder.args(params).await?;
};
let builder_output = builder.build();
let builder_output =
tx::build_tx(&provider, from, to, code, sig, args, tx, chain, etherscan_api_key).await?;

let cast = Cast::new(provider);

Expand Down
1 change: 1 addition & 0 deletions crates/cast/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::time::Instant;

pub mod cmd;
pub mod opts;
pub mod tx;

use opts::{Cast as Opts, CastSubcommand, ToBaseArgs};

Expand Down
73 changes: 73 additions & 0 deletions crates/cast/bin/tx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use alloy_primitives::Address;
use cast::{TxBuilder, TxBuilderOutput};
use ethers_core::types::NameOrAddress;
use ethers_providers::Middleware;
use eyre::Result;
use foundry_cli::opts::TransactionOpts;
use foundry_config::Chain;

/// Prevents a misconfigured hwlib from sending a transaction that defies user-specified --from
pub fn validate_from_address(
specified_from: Option<Address>,
signer_address: Address,
) -> Result<()> {
if let Some(specified_from) = specified_from {
if specified_from != signer_address {
eyre::bail!(
"\
The specified sender via CLI/env vars does not match the sender configured via
the hardware wallet's HD Path.
Please use the `--hd-path <PATH>` parameter to specify the BIP32 Path which
corresponds to the sender, or let foundry automatically detect it by not specifying any sender address."
)
}
}
Ok(())
}

/// Ensures the transaction is either a contract deployment or a recipient address is specified
pub fn validate_to_address(code: &Option<String>, to: &Option<NameOrAddress>) -> Result<()> {
if code.is_none() && to.is_none() {
eyre::bail!("Must specify a recipient address or contract code to deploy");
}
Ok(())
}

#[allow(clippy::too_many_arguments)]
pub async fn build_tx<M: Middleware, F: Into<NameOrAddress>, T: Into<NameOrAddress>>(
provider: &M,
from: F,
to: Option<T>,
code: Option<String>,
sig: Option<String>,
args: Vec<String>,
tx: TransactionOpts,
chain: impl Into<Chain>,
etherscan_api_key: Option<String>,
) -> Result<TxBuilderOutput> {
let mut builder = TxBuilder::new(provider, from, to, chain, tx.legacy).await?;
builder
.etherscan_api_key(etherscan_api_key)
.gas(tx.gas_limit)
.gas_price(tx.gas_price)
.priority_gas_price(tx.priority_gas_price)
.value(tx.value)
.nonce(tx.nonce);

let params = sig.as_deref().map(|sig| (sig, args));
if let Some(code) = code {
let mut data = hex::decode(code)?;

if let Some((sig, args)) = params {
let (mut sigdata, _) = builder.create_args(sig, args).await?;
data.append(&mut sigdata);
}

builder.set_data(data);
} else {
builder.args(params).await?;
}

let builder_output = builder.build();
Ok(builder_output)
}
4 changes: 2 additions & 2 deletions crates/cast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ use std::{
sync::atomic::{AtomicBool, Ordering},
};
use tokio::signal::ctrl_c;
use tx::{TxBuilderOutput, TxBuilderPeekOutput};
use tx::TxBuilderPeekOutput;

pub use foundry_evm::*;
pub use rusoto_core::{
credential::ChainProvider as AwsChainProvider, region::Region as AwsRegion,
request::HttpClient as AwsHttpClient, Client as AwsClient,
};
pub use rusoto_kms::KmsClient;
pub use tx::TxBuilder;
pub use tx::{TxBuilder, TxBuilderOutput};

pub mod base;
pub mod errors;
Expand Down

0 comments on commit 55d9f1a

Please sign in to comment.