diff --git a/crates/sncast/src/helpers/fee.rs b/crates/sncast/src/helpers/fee.rs index cbfae691c0..ddf78fa1c8 100644 --- a/crates/sncast/src/helpers/fee.rs +++ b/crates/sncast/src/helpers/fee.rs @@ -169,6 +169,22 @@ pub enum FeeSettings { }, } +impl From for FeeSettings { + fn from(value: ScriptFeeSettings) -> Self { + match value { + ScriptFeeSettings::Eth { max_fee } => FeeSettings::Eth { max_fee }, + ScriptFeeSettings::Strk { + max_gas, + max_gas_unit_price, + .. + } => FeeSettings::Strk { + max_gas, + max_gas_unit_price, + }, + } + } +} + pub trait PayableTransaction { fn error_message(&self, token: &str, version: &str) -> String; fn validate(&self) -> Result<()>; diff --git a/crates/sncast/src/lib.rs b/crates/sncast/src/lib.rs index 1ef493b6ea..ded59fa225 100644 --- a/crates/sncast/src/lib.rs +++ b/crates/sncast/src/lib.rs @@ -266,6 +266,19 @@ pub async fn get_account<'a>( Ok(account) } +pub async fn get_contract_class( + class_hash: Felt, + provider: &JsonRpcClient, +) -> Result { + provider + .get_class(BlockId::Tag(BlockTag::Latest), class_hash) + .await + .map_err(handle_rpc_error) + .context(format!( + "Couldn't retrieve contract class with hash: {class_hash:#x}" + )) +} + async fn build_account( account_data: AccountData, chain_id: Felt, diff --git a/crates/sncast/src/main.rs b/crates/sncast/src/main.rs index 842341f5ad..6245cf8fab 100644 --- a/crates/sncast/src/main.rs +++ b/crates/sncast/src/main.rs @@ -23,6 +23,7 @@ use sncast::{ chain_id_to_network_name, get_account, get_block_id, get_chain_id, get_default_state_file_name, NumbersFormat, ValidatedWaitParams, WaitForTx, }; +use starknet::accounts::ConnectedAccount; use starknet::core::utils::get_selector_from_name; use starknet::providers::Provider; use starknet_commands::account::list::print_account_list; @@ -221,9 +222,19 @@ async fn run_async_command( } Commands::Deploy(deploy) => { - let provider = deploy.rpc.get_provider(&config).await?; - deploy.validate()?; + + let fee_token = deploy.token_from_version(); + + let Deploy { + constructor_calldata, + fee_args, + rpc, + .. + } = deploy; + + let provider = rpc.get_provider(&config).await?; + let account = get_account( &config.account, &config.accounts_file, @@ -232,9 +243,24 @@ async fn run_async_command( ) .await?; - let result = starknet_commands::deploy::deploy(deploy, &account, wait_config) - .await - .map_err(handle_starknet_command_error); + let fee_settings = fee_args + .clone() + .fee_token(fee_token) + .try_into_fee_settings(&provider, account.block_id()) + .await?; + + let result = starknet_commands::deploy::deploy( + deploy.class_hash, + &constructor_calldata, + deploy.salt, + deploy.unique, + fee_settings, + deploy.nonce, + &account, + wait_config, + ) + .await + .map_err(handle_starknet_command_error); print_command_result("deploy", &result, numbers_format, output_format)?; print_block_explorer_link_if_allowed( @@ -247,16 +273,24 @@ async fn run_async_command( Ok(()) } - Commands::Call(call) => { - let provider = call.rpc.get_provider(&config).await?; + Commands::Call(Call { + contract_address, + function, + calldata, + block_id, + rpc, + }) => { + let provider = rpc.get_provider(&config).await?; + + let block_id = get_block_id(&block_id)?; - let block_id = get_block_id(&call.block_id)?; + let entry_point_selector = get_selector_from_name(&function) + .context("Failed to convert entry point selector to FieldElement")?; let result = starknet_commands::call::call( - call.contract_address, - get_selector_from_name(&call.function) - .context("Failed to convert entry point selector to FieldElement")?, - call.calldata, + contract_address, + entry_point_selector, + calldata, &provider, block_id.as_ref(), ) @@ -268,10 +302,22 @@ async fn run_async_command( } Commands::Invoke(invoke) => { - let provider = invoke.rpc.get_provider(&config).await?; - invoke.validate()?; + let fee_token = invoke.token_from_version(); + + let Invoke { + contract_address, + function, + calldata, + fee_args, + rpc, + nonce, + .. + } = invoke; + + let provider = rpc.get_provider(&config).await?; + let account = get_account( &config.account, &config.accounts_file, @@ -279,10 +325,18 @@ async fn run_async_command( config.keystore, ) .await?; + + let fee_args = fee_args.fee_token(fee_token); + + let selector = get_selector_from_name(&function) + .context("Failed to convert entry point selector to FieldElement")?; + let result = starknet_commands::invoke::invoke( - invoke.clone(), - get_selector_from_name(&invoke.function) - .context("Failed to convert entry point selector to FieldElement")?, + contract_address, + calldata, + nonce, + fee_args, + selector, &account, wait_config, ) diff --git a/crates/sncast/src/starknet_commands/account/add.rs b/crates/sncast/src/starknet_commands/account/add.rs index 0ba9c25fd6..c66c41efd5 100644 --- a/crates/sncast/src/starknet_commands/account/add.rs +++ b/crates/sncast/src/starknet_commands/account/add.rs @@ -22,7 +22,7 @@ pub struct Add { pub name: String, /// Address of the account - #[clap(short, long, requires = "private_key_input")] + #[clap(long, requires = "private_key_input")] pub address: Felt, /// Type of the account diff --git a/crates/sncast/src/starknet_commands/account/create.rs b/crates/sncast/src/starknet_commands/account/create.rs index 754c5171fb..f345d9fa67 100644 --- a/crates/sncast/src/starknet_commands/account/create.rs +++ b/crates/sncast/src/starknet_commands/account/create.rs @@ -46,7 +46,7 @@ pub struct Create { pub add_profile: Option, /// Custom contract class hash of declared contract - #[clap(short, long, requires = "account_type")] + #[clap(long, requires = "account_type")] pub class_hash: Option, #[clap(flatten)] diff --git a/crates/sncast/src/starknet_commands/account/list.rs b/crates/sncast/src/starknet_commands/account/list.rs index 61d92f5aa4..8bbef94a33 100644 --- a/crates/sncast/src/starknet_commands/account/list.rs +++ b/crates/sncast/src/starknet_commands/account/list.rs @@ -22,7 +22,7 @@ use std::fmt::Display; )] pub struct List { /// Display private keys - #[arg(short = 'p', long = "display-private-keys")] + #[arg(long = "display-private-keys")] pub display_private_keys: bool, } diff --git a/crates/sncast/src/starknet_commands/call.rs b/crates/sncast/src/starknet_commands/call.rs index 54ae9f3e35..8bddb636b1 100644 --- a/crates/sncast/src/starknet_commands/call.rs +++ b/crates/sncast/src/starknet_commands/call.rs @@ -11,21 +11,21 @@ use starknet::providers::{JsonRpcClient, Provider}; #[command(about = "Call a contract instance on Starknet", long_about = None)] pub struct Call { /// Address of the called contract (hex) - #[clap(short = 'a', long)] + #[clap(long)] pub contract_address: Felt, /// Name of the contract function to be called - #[clap(short, long)] + #[clap(long)] pub function: String, /// Arguments of the called function (list of hex) - #[clap(short, long, value_delimiter = ' ', num_args = 1..)] + #[clap(long, value_delimiter = ' ', num_args = 1..)] pub calldata: Vec, /// Block identifier on which call should be performed. /// Possible values: pending, latest, block hash (0x prefixed string) /// and block number (u64) - #[clap(short, long, default_value = "pending")] + #[clap(long, default_value = "pending")] pub block_id: String, #[clap(flatten)] diff --git a/crates/sncast/src/starknet_commands/declare.rs b/crates/sncast/src/starknet_commands/declare.rs index 822c669512..261829ba68 100644 --- a/crates/sncast/src/starknet_commands/declare.rs +++ b/crates/sncast/src/starknet_commands/declare.rs @@ -23,7 +23,7 @@ use std::sync::Arc; #[command(about = "Declare a contract to starknet", long_about = None)] pub struct Declare { /// Contract name - #[clap(short = 'c', long = "contract-name")] + #[clap(long = "contract-name")] pub contract: String, #[clap(flatten)] diff --git a/crates/sncast/src/starknet_commands/deploy.rs b/crates/sncast/src/starknet_commands/deploy.rs index b2a5ab96ce..b4361e60de 100644 --- a/crates/sncast/src/starknet_commands/deploy.rs +++ b/crates/sncast/src/starknet_commands/deploy.rs @@ -24,7 +24,7 @@ pub struct Deploy { pub class_hash: Felt, /// Calldata for the contract constructor - #[clap(short, long, value_delimiter = ' ', num_args = 1..)] + #[clap(long, value_delimiter = ' ', num_args = 1..)] pub constructor_calldata: Vec, /// Salt for the address @@ -61,29 +61,27 @@ impl_payable_transaction!(Deploy, token_not_supported_for_deployment, DeployVersion::V3 => FeeToken::Strk ); +#[allow(clippy::ptr_arg, clippy::too_many_arguments)] pub async fn deploy( - deploy: Deploy, + class_hash: Felt, + calldata: &Vec, + salt: Option, + unique: bool, + fee_settings: FeeSettings, + nonce: Option, account: &SingleOwnerAccount<&JsonRpcClient, LocalWallet>, wait_config: WaitForTx, ) -> Result { - let fee_settings = deploy - .fee_args - .clone() - .fee_token(deploy.token_from_version()) - .try_into_fee_settings(account.provider(), account.block_id()) - .await?; - - let salt = extract_or_generate_salt(deploy.salt); - let factory = ContractFactory::new(deploy.class_hash, account); + let salt = extract_or_generate_salt(salt); + let factory = ContractFactory::new(class_hash, account); let result = match fee_settings { FeeSettings::Eth { max_fee } => { - let execution = - factory.deploy_v1(deploy.constructor_calldata.clone(), salt, deploy.unique); + let execution = factory.deploy_v1(calldata.clone(), salt, unique); let execution = match max_fee { None => execution, Some(max_fee) => execution.max_fee(max_fee), }; - let execution = match deploy.nonce { + let execution = match nonce { None => execution, Some(nonce) => execution.nonce(nonce), }; @@ -93,8 +91,7 @@ pub async fn deploy( max_gas, max_gas_unit_price, } => { - let execution = - factory.deploy_v3(deploy.constructor_calldata.clone(), salt, deploy.unique); + let execution = factory.deploy_v3(calldata.clone(), salt, unique); let execution = match max_gas { None => execution, @@ -104,7 +101,7 @@ pub async fn deploy( None => execution, Some(max_gas_unit_price) => execution.gas_price(max_gas_unit_price), }; - let execution = match deploy.nonce { + let execution = match nonce { None => execution, Some(nonce) => execution.nonce(nonce), }; @@ -119,9 +116,9 @@ pub async fn deploy( DeployResponse { contract_address: get_udc_deployed_address( salt, - deploy.class_hash, - &udc_uniqueness(deploy.unique, account.address()), - &deploy.constructor_calldata, + class_hash, + &udc_uniqueness(unique, account.address()), + calldata, ), transaction_hash: result.transaction_hash, }, diff --git a/crates/sncast/src/starknet_commands/invoke.rs b/crates/sncast/src/starknet_commands/invoke.rs index 99558c8e47..dd492df4b0 100644 --- a/crates/sncast/src/starknet_commands/invoke.rs +++ b/crates/sncast/src/starknet_commands/invoke.rs @@ -17,15 +17,15 @@ use starknet::signers::LocalWallet; #[command(about = "Invoke a contract on Starknet")] pub struct Invoke { /// Address of contract to invoke - #[clap(short = 'a', long)] + #[clap(long)] pub contract_address: Felt, /// Name of the function to invoke - #[clap(short, long)] + #[clap(long)] pub function: String, /// Calldata for the invoked function - #[clap(short, long, value_delimiter = ' ', num_args = 1..)] + #[clap(long, value_delimiter = ' ', num_args = 1..)] pub calldata: Vec, #[clap(flatten)] @@ -55,23 +55,21 @@ impl_payable_transaction!(Invoke, token_not_supported_for_invoke, ); pub async fn invoke( - invoke: Invoke, + contract_address: Felt, + calldata: Vec, + nonce: Option, + fee_args: FeeArgs, function_selector: Felt, account: &SingleOwnerAccount<&JsonRpcClient, LocalWallet>, wait_config: WaitForTx, ) -> Result { - let fee_args = invoke - .fee_args - .clone() - .fee_token(invoke.token_from_version()); - let call = Call { - to: invoke.contract_address, + to: contract_address, selector: function_selector, - calldata: invoke.calldata.clone(), + calldata, }; - execute_calls(account, vec![call], fee_args, invoke.nonce, wait_config).await + execute_calls(account, vec![call], fee_args, nonce, wait_config).await } pub async fn execute_calls( diff --git a/crates/sncast/src/starknet_commands/script/run.rs b/crates/sncast/src/starknet_commands/script/run.rs index ce7220afe3..b004c37139 100644 --- a/crates/sncast/src/starknet_commands/script/run.rs +++ b/crates/sncast/src/starknet_commands/script/run.rs @@ -1,6 +1,4 @@ use crate::starknet_commands::declare::Declare; -use crate::starknet_commands::deploy::Deploy; -use crate::starknet_commands::invoke::Invoke; use crate::starknet_commands::{call, declare, deploy, invoke, tx_status}; use crate::{get_account, WaitForTx}; use anyhow::{anyhow, Context, Result}; @@ -37,7 +35,7 @@ use shared::utils::build_readable_text; use sncast::get_nonce; use sncast::helpers::configuration::CastConfig; use sncast::helpers::constants::SCRIPT_LIB_ARTIFACT_NAME; -use sncast::helpers::fee::ScriptFeeSettings; +use sncast::helpers::fee::{FeeSettings, ScriptFeeSettings}; use sncast::helpers::rpc::RpcArgs; use sncast::response::structs::ScriptRunResponse; use sncast::state::hashing::{ @@ -45,6 +43,7 @@ use sncast::state::hashing::{ }; use sncast::state::state_file::StateManager; use starknet::accounts::{Account, SingleOwnerAccount}; +use starknet::core::types::Felt; use starknet::core::types::{BlockId, BlockTag::Pending}; use starknet::providers::jsonrpc::HttpTransport; use starknet::providers::JsonRpcClient; @@ -156,25 +155,14 @@ impl<'a> ExtensionLogic for CastScriptExtension<'a> { } "deploy" => { let class_hash = input_reader.read()?; - let constructor_calldata = input_reader.read()?; + let constructor_calldata = input_reader.read::>()?; let salt = input_reader.read()?; let unique = input_reader.read()?; - let fee_args = input_reader.read::()?.into(); + let fee_args: FeeSettings = input_reader.read::()?.into(); let nonce = input_reader.read()?; - let deploy = Deploy { - class_hash, - constructor_calldata, - salt, - unique, - fee_args, - nonce, - version: None, - rpc: RpcArgs::default(), - }; - let deploy_tx_id = - generate_deploy_tx_id(class_hash, &deploy.constructor_calldata, salt, unique); + generate_deploy_tx_id(class_hash, &constructor_calldata, salt, unique); if let Some(success_output) = self.state.get_output_if_success(deploy_tx_id.as_str()) @@ -183,7 +171,12 @@ impl<'a> ExtensionLogic for CastScriptExtension<'a> { } let deploy_result = self.tokio_runtime.block_on(deploy::deploy( - deploy, + class_hash, + &constructor_calldata, + salt, + unique, + fee_args, + nonce, self.account()?, WaitForTx { wait: true, @@ -206,16 +199,6 @@ impl<'a> ExtensionLogic for CastScriptExtension<'a> { let fee_args = input_reader.read::()?.into(); let nonce = input_reader.read()?; - let invoke = Invoke { - contract_address, - function: String::new(), - calldata: calldata.clone(), - fee_args, - nonce, - version: None, - rpc: RpcArgs::default(), - }; - let invoke_tx_id = generate_invoke_tx_id(contract_address, function_selector, &calldata); @@ -226,7 +209,10 @@ impl<'a> ExtensionLogic for CastScriptExtension<'a> { } let invoke_result = self.tokio_runtime.block_on(invoke::invoke( - invoke, + contract_address, + calldata, + nonce, + fee_args, function_selector, self.account()?, WaitForTx { diff --git a/crates/sncast/src/starknet_commands/verify.rs b/crates/sncast/src/starknet_commands/verify.rs index 52d6435b31..9a7af22c01 100644 --- a/crates/sncast/src/starknet_commands/verify.rs +++ b/crates/sncast/src/starknet_commands/verify.rs @@ -114,11 +114,11 @@ impl VerificationInterface for WalnutVerificationInterface { #[command(about = "Verify a contract through a block explorer")] pub struct Verify { /// Address of a contract to be verified - #[clap(short = 'a', long)] + #[clap(long)] pub contract_address: Felt, /// Name of the contract that is being verified - #[clap(short, long)] + #[clap(long)] pub contract_name: String, /// Block explorer to use for the verification