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

Print max fee conversion info when using v3 txs #2797

Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
e843e47
Validate max gas is greater than zero for in for strk fee settings
franciszekjob Dec 18, 2024
196ac53
Print max fee conversion info when using v3 txs
franciszekjob Dec 18, 2024
beb7e67
Fix typo
franciszekjob Dec 18, 2024
52fa843
Adjust test
franciszekjob Dec 18, 2024
eacff90
Update `test_happy_case_strk`
franciszekjob Dec 18, 2024
ef43fae
Fix tests
franciszekjob Dec 18, 2024
0a2f5bb
Fix tests
franciszekjob Dec 18, 2024
ea50757
Merge branch 'master' into franciszekjob/2706-validate-fee-args-great…
franciszekjob Dec 18, 2024
8dce237
Check if max gas unit price > 0 when it's passed with max fee
franciszekjob Dec 18, 2024
72f2fe8
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 18, 2024
6dbe787
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 18, 2024
cb3d529
Refactor checking if feee args are greater than zero
franciszekjob Dec 18, 2024
a411a4e
Update error messages
franciszekjob Dec 18, 2024
dbbcf3f
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 18, 2024
397a8ba
Update docs and changelog
franciszekjob Dec 19, 2024
34770c3
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 19, 2024
77f4d4d
Update changelog
franciszekjob Dec 19, 2024
e5c22d2
Refactor checking if calculated value is zero
franciszekjob Dec 19, 2024
b2963a7
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 19, 2024
969e37b
Cover case when max fee and max gas unit price are passed
franciszekjob Dec 19, 2024
a6ed7db
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 19, 2024
436e51f
Display converted values in `print_max_fee_conversion_info`
franciszekjob Dec 19, 2024
ee9b354
Add newline ad the end of fee conversion message
franciszekjob Dec 19, 2024
4788a9b
Refactor `ScriptFeeSettings` and `FeeSettings`
franciszekjob Dec 19, 2024
e23e54e
Merge branch 'master' into franciszekjob/2706-validate-fee-args-great…
franciszekjob Dec 19, 2024
2a765a4
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 19, 2024
80916bf
Fix tests
franciszekjob Dec 20, 2024
31168e4
Format
franciszekjob Dec 20, 2024
69af0af
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 20, 2024
7b7337e
Rename `zero` to `0`
franciszekjob Dec 20, 2024
2db18e6
Update changelog
franciszekjob Dec 20, 2024
41e4cd5
Add `impl_deserialize_for_nonzero_num_type` macro
franciszekjob Dec 20, 2024
73e085f
Apply other code review suggestions
franciszekjob Dec 20, 2024
84d08ba
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Dec 20, 2024
69ed7c8
Fix linting
franciszekjob Jan 6, 2025
7d4bbed
Update changelog
franciszekjob Jan 7, 2025
0779442
Add conversions tests
franciszekjob Jan 7, 2025
45cf019
Merge branch 'master' of https://github.com/foundry-rs/starknet-found…
franciszekjob Jan 7, 2025
0c80350
Update changelog - remove duplicated entry
franciszekjob Jan 7, 2025
0e185b6
Fix headings in changelog
franciszekjob Jan 7, 2025
a784e69
Refactor `FeeArgs.try_into_fee_settings()`
franciszekjob Jan 7, 2025
091e484
Update `unreachable!` messages in `FeeArgs.try_into_fee_settings()`
franciszekjob Jan 7, 2025
9bb9f1a
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Jan 7, 2025
b32e7a4
Update crates/sncast/src/helpers/fee.rs
franciszekjob Jan 7, 2025
dd12975
Merge branch 'franciszekjob/2707-show-info-about-converted-max-fee-wi…
franciszekjob Jan 7, 2025
f161eff
Fix linting
franciszekjob Jan 10, 2025
7f1fbbc
Merge branch 'master' of https://github.com/foundry-rs/starknet-found…
franciszekjob Jan 10, 2025
9682eab
Use `Felt::TWO.pow`
franciszekjob Jan 10, 2025
a7c0acf
Remove use of `to_bigint()` in `impl_deserialize_for_num_type`
franciszekjob Jan 10, 2025
2eb48ae
Merge branch 'master' of https://github.com/foundry-rs/starknet-found…
franciszekjob Jan 10, 2025
56e3122
Merge branch 'master' into franciszekjob/2706-validate-fee-args-great…
franciszekjob Jan 14, 2025
5831be3
Merge branch 'master' into franciszekjob/2706-validate-fee-args-great…
franciszekjob Jan 14, 2025
e200723
Add todo
franciszekjob Jan 14, 2025
d8b0c51
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Jan 14, 2025
4d7229f
Add todo
franciszekjob Jan 14, 2025
756b5c7
Merge branch 'franciszekjob/2706-validate-fee-args-greater-than-zero'…
franciszekjob Jan 14, 2025
df06e53
Merge branch 'master' of https://github.com/foundry-rs/starknet-found…
franciszekjob Jan 14, 2025
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Cast

### Added

- When using `--max-fee` with transactions v3, calculated max gas and max gas unit price are automatically validated to ensure they are greater than 0 after conversion

### Changed

- Values passed to the `--max-fee`, `--max-gas`, and `--max-gas-unit-price` flags must be greater than 0

## [0.35.1] - 2024-12-16

### Forge
Expand Down
51 changes: 48 additions & 3 deletions crates/conversions/src/felt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ use crate::{
byte_array::ByteArray,
serde::serialize::SerializeToFeltVec,
string::{TryFromDecStr, TryFromHexStr},
FromConv, IntoConv,
FromConv, IntoConv, TryFromConv,
};
use conversions::padded_felt::PaddedFelt;
use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce};
use starknet_types_core::felt::{Felt, FromStrError};
use std::vec;
use starknet_types_core::felt::{Felt, FromStrError, NonZeroFelt};
use std::{
num::{NonZero, NonZeroU128, NonZeroU64},
vec,
};

impl FromConv<ClassHash> for Felt {
fn from_(value: ClassHash) -> Felt {
Expand Down Expand Up @@ -39,6 +42,48 @@ impl FromConv<PaddedFelt> for Felt {
}
}

impl TryFromConv<NonZeroFelt> for NonZeroU64 {
type Error = String;
fn try_from_(value: NonZeroFelt) -> Result<Self, Self::Error> {
let value: u64 = Felt::from(value)
.try_into()
.map_err(|_| "felt was too large to fit in u64")?;
Ok(NonZero::new(value)
.unwrap_or_else(|| unreachable!("non zero felt is always greater than 0")))
}
}

impl TryFromConv<NonZeroFelt> for NonZeroU128 {
type Error = String;
fn try_from_(value: NonZeroFelt) -> Result<Self, Self::Error> {
let value: u128 = Felt::from(value)
.try_into()
.map_err(|_| "felt was too large to fit in u128")?;
Ok(NonZero::new(value)
.unwrap_or_else(|| unreachable!("non zero felt is always greater than 0")))
}
}

impl FromConv<NonZeroU64> for NonZeroFelt {
fn from_(value: NonZeroU64) -> Self {
NonZeroFelt::try_from(Felt::from(value.get())).unwrap_or_else(|_| {
unreachable!(
"NonZeroU64 is always greater than 0, so it should be convertible to NonZeroFelt"
)
})
}
}

impl FromConv<NonZeroU128> for NonZeroFelt {
fn from_(value: NonZeroU128) -> Self {
NonZeroFelt::try_from(Felt::from(value.get())).unwrap_or_else(|_| {
unreachable!(
"NonZeroU128 is always greater than 0, so it should be convertible to NonZeroFelt"
)
})
}
}

impl<T> TryFromDecStr for T
where
T: FromConv<Felt>,
Expand Down
32 changes: 24 additions & 8 deletions crates/conversions/src/serde/deserialize/deserialize_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::{byte_array::ByteArray, IntoConv};
use num_traits::cast::ToPrimitive;
use starknet::providers::Url;
use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce};
use starknet_types_core::felt::Felt;
use std::num::NonZeroU32;
use starknet_types_core::felt::{Felt, NonZeroFelt};
use std::num::NonZero;

impl CairoDeserialize for Url {
fn deserialize(reader: &mut BufferReader<'_>) -> BufferReadResult<Self> {
Expand All @@ -13,12 +13,6 @@ impl CairoDeserialize for Url {
}
}

impl CairoDeserialize for NonZeroU32 {
fn deserialize(reader: &mut BufferReader<'_>) -> BufferReadResult<Self> {
NonZeroU32::new(reader.read()?).ok_or(BufferReadError::ParseFailed)
}
}

impl CairoDeserialize for Felt {
fn deserialize(reader: &mut BufferReader<'_>) -> BufferReadResult<Self> {
reader.read_felt()
Expand Down Expand Up @@ -71,6 +65,24 @@ impl CairoDeserialize for bool {
}
}

impl CairoDeserialize for NonZeroFelt {
fn deserialize(reader: &mut BufferReader<'_>) -> BufferReadResult<Self> {
let felt = reader.read::<Felt>()?;
NonZeroFelt::try_from(felt).map_err(|_| BufferReadError::ParseFailed)
}
}

macro_rules! impl_deserialize_for_nonzero_num_type {
($type:ty) => {
impl CairoDeserialize for NonZero<$type> {
fn deserialize(reader: &mut BufferReader<'_>) -> BufferReadResult<Self> {
let val = <$type>::deserialize(reader)?;
NonZero::new(val).ok_or(BufferReadError::ParseFailed)
}
}
};
}

macro_rules! impl_deserialize_for_felt_type {
($type:ty) => {
impl CairoDeserialize for $type {
Expand Down Expand Up @@ -99,6 +111,10 @@ impl_deserialize_for_felt_type!(ContractAddress);
impl_deserialize_for_felt_type!(Nonce);
impl_deserialize_for_felt_type!(EntryPointSelector);

impl_deserialize_for_nonzero_num_type!(u32);
impl_deserialize_for_nonzero_num_type!(u64);
impl_deserialize_for_nonzero_num_type!(u128);

impl_deserialize_for_num_type!(u8);
impl_deserialize_for_num_type!(u16);
impl_deserialize_for_num_type!(u32);
Expand Down
145 changes: 95 additions & 50 deletions crates/sncast/src/helpers/fee.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use anyhow::{bail, ensure, Error, Result};
use anyhow::{bail, ensure, Context, Error, Result};
use clap::{Args, ValueEnum};
use conversions::serde::deserialize::CairoDeserialize;
use conversions::TryIntoConv;
use conversions::{serde::deserialize::CairoDeserialize, FromConv, TryFromConv};
use shared::print::print_as_warning;
use starknet::core::types::BlockId;
use starknet::providers::Provider;
use starknet_types_core::felt::{Felt, NonZeroFelt};
use std::str::FromStr;
use std::{
num::{NonZeroU128, NonZeroU64},
str::FromStr,
};

#[derive(Args, Debug, Clone)]
pub struct FeeArgs {
Expand All @@ -15,16 +17,16 @@ pub struct FeeArgs {
pub fee_token: Option<FeeToken>,

/// Max fee for the transaction. If not provided, will be automatically estimated.
#[clap(short, long)]
pub max_fee: Option<Felt>,
#[clap(value_parser = parse_non_zero_felt, short, long)]
pub max_fee: Option<NonZeroFelt>,

/// Max gas amount. If not provided, will be automatically estimated. (Only for STRK fee payment)
#[clap(long)]
pub max_gas: Option<Felt>,
#[clap(value_parser = parse_non_zero_felt, long)]
pub max_gas: Option<NonZeroFelt>,

/// Max gas price in Fri. If not provided, will be automatically estimated. (Only for STRK fee payment)
#[clap(long)]
pub max_gas_unit_price: Option<Felt>,
#[clap(value_parser = parse_non_zero_felt, long)]
pub max_gas_unit_price: Option<NonZeroFelt>,
}

impl From<ScriptFeeSettings> for FeeArgs {
Expand All @@ -43,8 +45,8 @@ impl From<ScriptFeeSettings> for FeeArgs {
} => Self {
fee_token: Some(FeeToken::Strk),
max_fee,
max_gas: max_gas.map(Into::into),
max_gas_unit_price: max_gas_unit_price.map(Into::into),
max_gas: max_gas.map(NonZeroFelt::from_),
max_gas_unit_price: max_gas_unit_price.map(NonZeroFelt::from_),
},
}
}
Expand All @@ -59,6 +61,7 @@ impl FeeArgs {
}
}

#[allow(clippy::too_many_lines)]
pub async fn try_into_fee_settings<P: Provider>(
&self,
provider: P,
Expand Down Expand Up @@ -92,44 +95,74 @@ impl FeeArgs {
bail!("--max-fee should be greater than or equal to --max-gas-unit-price")
}
(None, _, _) => FeeSettings::Strk {
max_gas: self.max_gas.map(TryIntoConv::try_into_).transpose()?,
max_gas: self
.max_gas
.map(NonZeroU64::try_from_)
.transpose()
.map_err(anyhow::Error::msg)?,
max_gas_unit_price: self
.max_gas_unit_price
.map(TryIntoConv::try_into_)
.transpose()?,
},
(Some(max_fee), None, Some(max_gas_unit_price)) => FeeSettings::Strk {
max_gas: Some(
max_fee
.floor_div(&NonZeroFelt::from_felt_unchecked(max_gas_unit_price))
.try_into_()?,
),
max_gas_unit_price: Some(max_gas_unit_price.try_into_()?),
},
(Some(max_fee), Some(max_gas), None) => FeeSettings::Strk {
max_gas: Some(max_gas.try_into_()?),
max_gas_unit_price: Some(
max_fee
.floor_div(&NonZeroFelt::from_felt_unchecked(max_gas))
.try_into_()?,
),
.map(NonZeroU128::try_from_)
.transpose()
.map_err(anyhow::Error::msg)?,
},
(Some(max_fee), None, Some(max_gas_unit_price)) => {
let max_gas = NonZeroFelt::try_from(Felt::from(max_fee).floor_div(&max_gas_unit_price)).context("Calculated max gas from provided --max-fee and --max-gas-unit-price is 0. Please increase --max-fee to obtain a positive gas amount")?;
print_max_fee_conversion_info(
max_fee.into(),
max_gas.into(),
max_gas_unit_price.into(),
);
FeeSettings::Strk {
max_gas: Some(
NonZeroU64::try_from_(max_gas).map_err(anyhow::Error::msg)?,
),
max_gas_unit_price: Some(
NonZeroU128::try_from_(max_gas_unit_price)
.map_err(anyhow::Error::msg)?,
),
}
}
(Some(max_fee), Some(max_gas), None) => {
let max_gas_unit_price = NonZeroFelt::try_from(Felt::from(max_fee).floor_div(&max_gas)).context("Calculated max gas unit price from provided --max-fee and --max-gas is 0. Please increase --max-fee or decrease --max-gas to ensure a positive gas unit price")?;
print_max_fee_conversion_info(
max_fee.into(),
max_gas.into(),
max_gas_unit_price.into(),
);
FeeSettings::Strk {
max_gas: Some(
NonZeroU64::try_from_(max_gas).map_err(anyhow::Error::msg)?,
),
max_gas_unit_price: Some(
NonZeroU128::try_from_(max_gas_unit_price)
.map_err(anyhow::Error::msg)?,
),
}
}
(Some(max_fee), None, None) => {
let max_gas_unit_price = provider
.get_block_with_tx_hashes(block_id)
.await?
.l1_gas_price()
.price_in_fri;

let max_gas_unit_price = NonZeroFelt::try_from(
provider
.get_block_with_tx_hashes(block_id)
.await?
.l1_gas_price()
.price_in_fri,
)?;
let max_gas = NonZeroFelt::try_from(Felt::from(max_fee)
.floor_div(&max_gas_unit_price)).context("Calculated max-gas from provided --max-fee and the current network gas price is 0. Please increase --max-fee to obtain a positive gas amount")?;
print_max_fee_conversion_info(
max_fee.into(),
max_gas.into(),
max_gas_unit_price.into(),
);
FeeSettings::Strk {
max_gas: Some(
max_fee
.floor_div(&NonZeroFelt::from_felt_unchecked(
max_gas_unit_price,
))
.try_into_()?,
NonZeroU64::try_from_(max_gas).map_err(anyhow::Error::msg)?,
),
max_gas_unit_price: Some(
NonZeroU128::try_from_(max_gas_unit_price)
.map_err(anyhow::Error::msg)?,
),
max_gas_unit_price: Some(max_gas_unit_price.try_into_()?),
}
}
};
Expand All @@ -152,23 +185,23 @@ pub enum FeeToken {
#[derive(Debug, PartialEq, CairoDeserialize)]
pub enum ScriptFeeSettings {
Eth {
max_fee: Option<Felt>,
max_fee: Option<NonZeroFelt>,
},
Strk {
max_fee: Option<Felt>,
max_gas: Option<u64>,
max_gas_unit_price: Option<u128>,
max_fee: Option<NonZeroFelt>,
max_gas: Option<NonZeroU64>,
max_gas_unit_price: Option<NonZeroU128>,
},
}

#[derive(Debug, PartialEq)]
pub enum FeeSettings {
Eth {
max_fee: Option<Felt>,
max_fee: Option<NonZeroFelt>,
},
Strk {
max_gas: Option<u64>,
max_gas_unit_price: Option<u128>,
max_gas: Option<NonZeroU64>,
max_gas_unit_price: Option<NonZeroU128>,
},
}

Expand Down Expand Up @@ -261,3 +294,15 @@ fn parse_fee_token(s: &str) -> Result<FeeToken, String> {

Ok(parsed_token)
}

fn print_max_fee_conversion_info(max_fee: Felt, max_gas: Felt, max_gas_unit_price: Felt) {
println!(
franciszekjob marked this conversation as resolved.
Show resolved Hide resolved
"Specifying '--max-fee' flag while using v3 transactions results in conversion to '--max-gas' and '--max-gas-unit-price' flags\nConverted {max_fee} max fee to {max_gas} max gas and {max_gas_unit_price} max gas unit price\n",
);
}

fn parse_non_zero_felt(s: &str) -> Result<NonZeroFelt, String> {
let felt: Felt = s.parse().map_err(|_| "Failed to parse value")?;
felt.try_into()
.map_err(|_| "Value should be greater than 0".to_string())
}
14 changes: 11 additions & 3 deletions crates/sncast/src/starknet_commands/account/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,18 +263,26 @@ where
let result = match fee_settings {
FeeSettings::Eth { max_fee } => {
let deployment = account_factory.deploy_v1(salt);
let deployment = apply_optional(deployment, max_fee, AccountDeploymentV1::max_fee);
let deployment = apply_optional(
deployment,
max_fee.map(Felt::from),
AccountDeploymentV1::max_fee,
);
deployment.send().await
}
FeeSettings::Strk {
max_gas,
max_gas_unit_price,
} => {
let deployment = account_factory.deploy_v3(salt);
let deployment = apply_optional(deployment, max_gas, AccountDeploymentV3::gas);
let deployment = apply_optional(
deployment,
max_gas_unit_price,
max_gas.map(std::num::NonZero::get),
AccountDeploymentV3::gas,
);
let deployment = apply_optional(
deployment,
max_gas_unit_price.map(std::num::NonZero::get),
AccountDeploymentV3::gas_price,
);
deployment.send().await
Expand Down
Loading
Loading