Skip to content

Commit

Permalink
feat: allow manually specifying max_fee
Browse files Browse the repository at this point in the history
Adds 2 new options: `--max-fee` for values in Ether and `--max-fee-raw`
for values in Wei.
  • Loading branch information
xJonathanLEI committed Jul 16, 2023
1 parent b0d90fb commit 7c197e0
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 112 deletions.
23 changes: 22 additions & 1 deletion Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ description = "Starkli (/ˈstɑːrklaɪ/), a blazing fast CLI tool for Starknet
anyhow = "1.0.71"
async-trait = "0.1.68"
auto_impl = "1.1.0"
bigdecimal = "0.4.1"
cairo-starknet-2-0-1 = { package = "cairo-lang-starknet", version = "=2.0.1" }
chrono = "0.4.26"
clap = { version = "4.3.8", features = ["derive", "env", "string"] }
Expand All @@ -21,6 +22,7 @@ hex = "0.4.3"
hex-literal = "0.4.1"
log = "0.4.19"
num-bigint = "0.4.3"
num-integer = "0.1.45"
regex = "1.8.4"
rpassword = "7.2.0"
serde = { version = "1.0.164", features = ["derive"] }
Expand Down
61 changes: 61 additions & 0 deletions src/fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use anyhow::Result;
use bigdecimal::BigDecimal;
use clap::Parser;
use starknet::{core::types::FieldElement, macros::felt};

use crate::utils::bigdecimal_to_felt;

#[derive(Debug, Clone, Parser)]
pub struct FeeArgs {
#[clap(long, help = "Maximum transaction fee in Ether (18 decimals)")]
max_fee: Option<BigDecimal>,
#[clap(long, help = "Maximum transaction fee in Wei")]
max_fee_raw: Option<FieldElement>,
#[clap(
long,
help = "Only estimate transaction fee without sending transaction"
)]
estimate_only: bool,
}

#[derive(Debug)]
pub enum FeeSetting {
Manual(FieldElement),
EstimateOnly,
None,
}

impl FeeArgs {
pub fn into_setting(self) -> Result<FeeSetting> {
match (self.max_fee, self.max_fee_raw, self.estimate_only) {
(Some(max_fee), None, false) => {
let max_fee_felt = bigdecimal_to_felt(&max_fee, 18)?;

// The user is most likely making a mistake for using a max fee higher than 1 ETH
// TODO: allow skipping this safety check
if max_fee_felt > felt!("1000000000000000000") {
anyhow::bail!(
"the --max-fee value is too large. \
--max-fee expects a value in Ether (18 decimals). \
Use --max-fee-raw instead to use a raw max_fee amount in Wei."
)
}

Ok(FeeSetting::Manual(max_fee_felt))
}
(None, Some(max_fee_raw), false) => Ok(FeeSetting::Manual(max_fee_raw)),
(None, None, true) => Ok(FeeSetting::EstimateOnly),
(None, None, false) => Ok(FeeSetting::None),
_ => Err(anyhow::anyhow!(
"invalid fee option. \
At most one of --max-fee, --max-fee-raw, and --estimate-only can be used."
)),
}
}
}

impl FeeSetting {
pub fn is_estimate_only(&self) -> bool {
matches!(self, FeeSetting::EstimateOnly)
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod casm;
mod chain_id;
mod compiler;
mod decode;
mod fee;
mod network;
mod provider;
mod signer;
Expand Down
96 changes: 71 additions & 25 deletions src/subcommands/account/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use starknet::{

use crate::{
account::{AccountConfig, AccountVariant, DeployedStatus, DeploymentStatus},
fee::{FeeArgs, FeeSetting},
signer::SignerArgs,
utils::watch_tx,
verbosity::VerbosityArgs,
Expand All @@ -24,21 +25,30 @@ pub struct Deploy {
provider: ProviderArgs,
#[clap(flatten)]
signer: SignerArgs,
#[clap(
long,
help = "Only estimate transaction fee without sending transaction"
)]
estimate_only: bool,
#[clap(flatten)]
fee: FeeArgs,
#[clap(help = "Path to the account config file")]
file: PathBuf,
#[clap(flatten)]
verbosity: VerbosityArgs,
}

enum MaxFeeType {
Manual {
max_fee: FieldElement,
},
Estimated {
estimate: FieldElement,
estimate_with_buffer: FieldElement,
},
}

impl Deploy {
pub async fn run(self) -> Result<()> {
self.verbosity.setup_logging();

let fee_setting = self.fee.into_setting()?;

let provider = Arc::new(self.provider.into_provider());
let signer = Arc::new(self.signer.into_signer()?);

Expand Down Expand Up @@ -90,29 +100,53 @@ impl Deploy {
panic!("Unexpected account deployment address mismatch");
}

// TODO: add option for manually specifying fees
let estimated_fee = account_deployment.estimate_fee().await?.overall_fee;
let max_fee = match fee_setting {
FeeSetting::Manual(fee) => MaxFeeType::Manual { max_fee: fee },
FeeSetting::EstimateOnly | FeeSetting::None => {
let estimated_fee = account_deployment.estimate_fee().await?.overall_fee;

// TODO: make buffer configurable
let estimated_fee_with_buffer = estimated_fee * 3 / 2;
// TODO: make buffer configurable
let estimated_fee_with_buffer = estimated_fee * 3 / 2;

let estimated_fee: FieldElement = estimated_fee.into();
if self.estimate_only {
println!(
"{} ETH",
format!("{}", estimated_fee.to_big_decimal(18)).bright_yellow(),
);
return Ok(());
}
let estimated_fee: FieldElement = estimated_fee.into();

let estimated_fee_with_buffer: FieldElement = estimated_fee_with_buffer.into();
if fee_setting.is_estimate_only() {
println!(
"{} ETH",
format!("{}", estimated_fee.to_big_decimal(18)).bright_yellow(),
);
return Ok(());
}

MaxFeeType::Estimated {
estimate: estimated_fee,
estimate_with_buffer: estimated_fee_with_buffer.into(),
}
}
};

match max_fee {
MaxFeeType::Manual { max_fee } => {
eprintln!(
"You've manually specified the account deployment fee to be {}. \
Therefore, fund at least:\n {}",
format!("{} ETH", max_fee.to_big_decimal(18)).bright_yellow(),
format!("{} ETH", max_fee.to_big_decimal(18)).bright_yellow(),
);
}
MaxFeeType::Estimated {
estimate,
estimate_with_buffer,
} => {
eprintln!(
"The estimated account deployment fee is {}. \
However, to avoid failure, fund at least:\n {}",
format!("{} ETH", estimate.to_big_decimal(18)).bright_yellow(),
format!("{} ETH", estimate_with_buffer.to_big_decimal(18)).bright_yellow()
);
}
}

eprintln!(
"The estimated account deployment fee is {}. \
However, to avoid failure, fund at least:\n {}",
format!("{} ETH", estimated_fee.to_big_decimal(18)).bright_yellow(),
format!("{} ETH", estimated_fee_with_buffer.to_big_decimal(18)).bright_yellow()
);
eprintln!(
"to the following address:\n {}",
format!("{:#064x}", target_deployment_address).bright_yellow()
Expand All @@ -124,7 +158,7 @@ impl Deploy {

// TODO: add option to check ETH balance before sending out tx
let account_deployment_tx = account_deployment
.max_fee(estimated_fee_with_buffer)
.max_fee(max_fee.max_fee())
.send()
.await?
.transaction_hash;
Expand Down Expand Up @@ -166,3 +200,15 @@ impl Deploy {
Ok(())
}
}

impl MaxFeeType {
pub fn max_fee(&self) -> FieldElement {
match self {
Self::Manual { max_fee } => *max_fee,
Self::Estimated {
estimate_with_buffer,
..
} => *estimate_with_buffer,
}
}
}
Loading

0 comments on commit 7c197e0

Please sign in to comment.