From b384a89da0ee0b4163918883a7d441c63da4f1b5 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 3 Nov 2024 15:18:35 +0530 Subject: [PATCH 01/25] Update execute.rs Added multi-call support to sozo exceute command --- bin/sozo/src/commands/execute.rs | 103 +++++++++++++++++-------------- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 038e4afa40..039b75b602 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -20,6 +20,27 @@ use crate::utils; #[derive(Debug, Args)] #[command(about = "Execute a system with the given calldata.")] pub struct ExecuteArgs { + + #[arg( + help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." + )] + + pub calls: Vec, + + #[command(flatten)] + pub starknet: StarknetOptions, + + #[command(flatten)] + pub account: AccountOptions, + + #[command(flatten)] + pub world: WorldOptions, + + #[command(flatten)] + pub transaction: TransactionOptions, +} + +pub struct CallArgs { #[arg( help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." )] @@ -38,18 +59,6 @@ pub struct ExecuteArgs { - int: A signed integer. - no prefix: A cairo felt or any type that fit into one felt.")] pub calldata: Option, - - #[command(flatten)] - pub starknet: StarknetOptions, - - #[command(flatten)] - pub account: AccountOptions, - - #[command(flatten)] - pub world: WorldOptions, - - #[command(flatten)] - pub transaction: TransactionOptions, } impl ExecuteArgs { @@ -82,42 +91,44 @@ impl ExecuteArgs { ) .await?; - let contract_address = match &descriptor { - ResourceDescriptor::Address(address) => Some(*address), - ResourceDescriptor::Tag(tag) => { - let selector = naming::compute_selector_from_tag(tag); - world_diff.get_contract_address(selector) - } - ResourceDescriptor::Name(_) => { - unimplemented!("Expected to be a resolved tag with default namespace.") + for call_args in self.calls { + let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); + + let contract_address = match &descriptor { + ResourceDescriptor::Address(address) => Some(*address), + ResourceDescriptor::Tag(tag) => { + let selector = naming::compute_selector_from_tag(tag); + world_diff.get_contract_address(selector) + } + ResourceDescriptor::Name(_) => { + unimplemented!("Expected to be a resolved tag with default namespace.") + } } + .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff."))?; + + trace!( + contract=?descriptor, + entrypoint=call_args.entrypoint, + calldata=?call_args.calldata, + "Executing Execute command." + ); + + let calldata = if let Some(cd) = call_args.calldata { + calldata_decoder::decode_calldata(&cd)? + } else { + vec![] + }; + let call = Call { + calldata, + to: contract_address, + selector: snutils::get_selector_from_name(&call_args.entrypoint)?, + }; + + let invoker = Invoker::new(&account, txn_config); + let tx_result = invoker.invoke(call).await?; + + println!("{}", tx_result); } - .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff."))?; - - trace!( - contract=?descriptor, - entrypoint=self.entrypoint, - calldata=?self.calldata, - "Executing Execute command." - ); - - let calldata = if let Some(cd) = self.calldata { - calldata_decoder::decode_calldata(&cd)? - } else { - vec![] - }; - - let call = Call { - calldata, - to: contract_address, - selector: snutils::get_selector_from_name(&self.entrypoint)?, - }; - - let invoker = Invoker::new(&account, txn_config); - // TODO: add walnut back, perhaps at the invoker level. - let tx_result = invoker.invoke(call).await?; - - println!("{}", tx_result); Ok(()) }) } From ae378aacc2fa6c1a5d16852d31953346010d0c70 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 3 Nov 2024 16:57:55 +0530 Subject: [PATCH 02/25] Few minor changes --- bin/sozo/src/commands/execute.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 039b75b602..d973ce422e 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -25,7 +25,7 @@ pub struct ExecuteArgs { help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." )] - pub calls: Vec, + pub calls: Vec, #[command(flatten)] pub starknet: StarknetOptions, @@ -40,6 +40,7 @@ pub struct ExecuteArgs { pub transaction: TransactionOptions, } +#[derive(Debug, Args)] pub struct CallArgs { #[arg( help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." From 5751ee7c33b8e14bf8ab25d559b73c663c9b804b Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Mon, 4 Nov 2024 08:58:02 +0530 Subject: [PATCH 03/25] Keeping vec string --- bin/sozo/src/commands/execute.rs | 67 +++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index d973ce422e..0a4604d6ab 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -25,7 +25,7 @@ pub struct ExecuteArgs { help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." )] - pub calls: Vec, + pub calls: Vec, #[command(flatten)] pub starknet: StarknetOptions, @@ -40,26 +40,42 @@ pub struct ExecuteArgs { pub transaction: TransactionOptions, } -#[derive(Debug, Args)] -pub struct CallArgs { - #[arg( - help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." - )] - pub tag_or_address: ResourceDescriptor, - - #[arg(help = "The name of the entrypoint to be executed.")] - pub entrypoint: String, - - #[arg(short, long)] - #[arg(help = "The calldata to be passed to the system. Comma separated values e.g., \ - 0x12345,128,u256:9999999999. Sozo supports some prefixes that you can use to \ - automatically parse some types. The supported prefixes are: - - u256: A 256-bit unsigned integer. - - sstr: A cairo short string. - - str: A cairo string (ByteArray). - - int: A signed integer. - - no prefix: A cairo felt or any type that fit into one felt.")] - pub calldata: Option, +// #[derive(Debug, Args)] +// pub struct CallArgs { +// #[arg( +// help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." +// )] +// pub tag_or_address: ResourceDescriptor, + +// #[arg(help = "The name of the entrypoint to be executed.")] +// pub entrypoint: String, + +// #[arg(short, long)] +// #[arg(help = "The calldata to be passed to the system. Comma separated values e.g., \ +// 0x12345,128,u256:9999999999. Sozo supports some prefixes that you can use to \ +// automatically parse some types. The supported prefixes are: +// - u256: A 256-bit unsigned integer. +// - sstr: A cairo short string. +// - str: A cairo string (ByteArray). +// - int: A signed integer. +// - no prefix: A cairo felt or any type that fit into one felt.")] +// pub calldata: Option, +// } + + +impl CallArgs { + fn from_string(s: &str) -> Result { + let parts: Vec<&str> = s.split(',').collect(); + if parts.len() < 2 { + return Err(anyhow!("Invalid call format")); + } + + Ok(CallArgs { + tag_or_address: parts[0].parse()?, + entrypoint: parts[1].to_string(), + calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, + }) + } } impl ExecuteArgs { @@ -92,7 +108,11 @@ impl ExecuteArgs { ) .await?; - for call_args in self.calls { + let call_args_list: Vec = self.calls.iter() + .map(|s| CallArgs::from_string(s)) + .collect::>>()?; + + for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); let contract_address = match &descriptor { @@ -119,6 +139,7 @@ impl ExecuteArgs { } else { vec![] }; + let call = Call { calldata, to: contract_address, @@ -131,6 +152,8 @@ impl ExecuteArgs { println!("{}", tx_result); } Ok(()) + + }) } } From 86777074d80c1399ade6a5454bb77f14c7c77c82 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Wed, 6 Nov 2024 10:30:25 +0530 Subject: [PATCH 04/25] Sperating each call using commas --- bin/sozo/src/commands/execute.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 0a4604d6ab..11253b16ae 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -62,6 +62,12 @@ pub struct ExecuteArgs { // pub calldata: Option, // } +#[derive(Debug)] +pub struct CallArgs { + pub tag_or_address: ResourceDescriptor, + pub entrypoint: String, + pub calldata: Option, +} impl CallArgs { fn from_string(s: &str) -> Result { @@ -71,13 +77,29 @@ impl CallArgs { } Ok(CallArgs { - tag_or_address: parts[0].parse()?, + tag_or_address: parts[0].parse()?, entrypoint: parts[1].to_string(), calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, }) } } + +// impl CallArgs { +// fn from_string(s: &str) -> Result { +// let parts: Vec<&str> = s.split(',').collect(); +// if parts.len() < 2 { +// return Err(anyhow!("Invalid call format")); +// } + +// Ok(CallArgs { +// tag_or_address: parts[0].parse()?, +// entrypoint: parts[1].to_string(), +// calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, +// }) +// } +// } + impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { trace!(args = ?self); From eebf6513c7d1b994e5faf9346ae6d9053ebfbd88 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Fri, 8 Nov 2024 15:34:50 +0530 Subject: [PATCH 05/25] Implementing Invoker before for loop and creating sep function for contract address --- bin/sozo/src/commands/execute.rs | 78 +++++++++++--------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 11253b16ae..a3726c475e 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -22,7 +22,7 @@ use crate::utils; pub struct ExecuteArgs { #[arg( - help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." + help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." )] pub calls: Vec, @@ -40,28 +40,6 @@ pub struct ExecuteArgs { pub transaction: TransactionOptions, } -// #[derive(Debug, Args)] -// pub struct CallArgs { -// #[arg( -// help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." -// )] -// pub tag_or_address: ResourceDescriptor, - -// #[arg(help = "The name of the entrypoint to be executed.")] -// pub entrypoint: String, - -// #[arg(short, long)] -// #[arg(help = "The calldata to be passed to the system. Comma separated values e.g., \ -// 0x12345,128,u256:9999999999. Sozo supports some prefixes that you can use to \ -// automatically parse some types. The supported prefixes are: -// - u256: A 256-bit unsigned integer. -// - sstr: A cairo short string. -// - str: A cairo string (ByteArray). -// - int: A signed integer. -// - no prefix: A cairo felt or any type that fit into one felt.")] -// pub calldata: Option, -// } - #[derive(Debug)] pub struct CallArgs { pub tag_or_address: ResourceDescriptor, @@ -73,7 +51,7 @@ impl CallArgs { fn from_string(s: &str) -> Result { let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { - return Err(anyhow!("Invalid call format")); + return Err(anyhow!("Invalid call format. Expected format: ,,,,...")); } Ok(CallArgs { @@ -84,21 +62,24 @@ impl CallArgs { } } +fn resolve_contract_address( + descriptor: &ResourceDescriptor, + world_diff: &WorldDiff, +) -> Result
{ + match descriptor { + ResourceDescriptor::Address(address) => Ok(*address), + ResourceDescriptor::Tag(tag) => { + let selector = naming::compute_selector_from_tag(tag); + world_diff + .get_contract_address(selector) + .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff.")) + } + ResourceDescriptor::Name(_) => { + unimplemented!("Expected to be a resolved tag with default namespace.") + } + } +} -// impl CallArgs { -// fn from_string(s: &str) -> Result { -// let parts: Vec<&str> = s.split(',').collect(); -// if parts.len() < 2 { -// return Err(anyhow!("Invalid call format")); -// } - -// Ok(CallArgs { -// tag_or_address: parts[0].parse()?, -// entrypoint: parts[1].to_string(), -// calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, -// }) -// } -// } impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { @@ -130,6 +111,8 @@ impl ExecuteArgs { ) .await?; + let mut invoker = Invoker::new(&account, txn_config); + let call_args_list: Vec = self.calls.iter() .map(|s| CallArgs::from_string(s)) .collect::>>()?; @@ -137,17 +120,7 @@ impl ExecuteArgs { for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); - let contract_address = match &descriptor { - ResourceDescriptor::Address(address) => Some(*address), - ResourceDescriptor::Tag(tag) => { - let selector = naming::compute_selector_from_tag(tag); - world_diff.get_contract_address(selector) - } - ResourceDescriptor::Name(_) => { - unimplemented!("Expected to be a resolved tag with default namespace.") - } - } - .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff."))?; + let contract_address = resolve_contract_address(&descriptor, &world_diff)?; trace!( contract=?descriptor, @@ -168,11 +141,12 @@ impl ExecuteArgs { selector: snutils::get_selector_from_name(&call_args.entrypoint)?, }; - let invoker = Invoker::new(&account, txn_config); - let tx_result = invoker.invoke(call).await?; + invoker.add_call(call); - println!("{}", tx_result); + } + let tx_result = invoker.invoke().await?; + println!("{}", tx_result); Ok(()) From 1ee5e0adb13d2859a2251b095cf9204c00dfc7e9 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Fri, 8 Nov 2024 15:53:02 +0530 Subject: [PATCH 06/25] Using the Fromstr trait for string operations --- bin/sozo/src/commands/execute.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index a3726c475e..c43ca8f559 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -1,5 +1,6 @@ use anyhow::{anyhow, Result}; use clap::Args; +use std::str::FromStr; use dojo_types::naming; use dojo_utils::{Invoker, TxnConfig}; use scarb::core::Config; @@ -22,7 +23,7 @@ use crate::utils; pub struct ExecuteArgs { #[arg( - help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." + help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" )] pub calls: Vec, @@ -47,16 +48,31 @@ pub struct CallArgs { pub calldata: Option, } -impl CallArgs { - fn from_string(s: &str) -> Result { ++impl std::str::FromStr for CallArgs { + + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let s = s.trim(); + if s.is_empty() { + return Err(anyhow!("Empty call string")); + } + let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { return Err(anyhow!("Invalid call format. Expected format: ,,,,...")); } + let entrypoint = parts[1].trim(); + if entrypoint.is_empty() { + return Err(anyhow!("Empty entrypoint")); + } + if !entrypoint.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { + return Err(anyhow!("Invalid entrypoint format. Must contain only alphanumeric characters and underscores")); + } Ok(CallArgs { tag_or_address: parts[0].parse()?, - entrypoint: parts[1].to_string(), + entrypoint: entrypoint.to_string(), calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, }) } From b3ed18217a25b00a233c4fce2862589cea60a133 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 10 Nov 2024 10:02:50 +0530 Subject: [PATCH 07/25] Checking local manifest for contract tag --- bin/sozo/src/commands/execute.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index c43ca8f559..87d418789d 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -136,7 +136,13 @@ impl ExecuteArgs { for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); - let contract_address = resolve_contract_address(&descriptor, &world_diff)?; + + // Checking the contract tag in local manifest + let contract_address = if let Some(local_address) = ws.get_contract_address(&descriptor) { + local_address + } else { + resolve_contract_address(&descriptor, &world_diff)? + }; trace!( contract=?descriptor, From ce9e1b4804561a9fccbac9417ef9aa330108fcd2 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 10 Nov 2024 18:25:59 +0530 Subject: [PATCH 08/25] dummy commit --- bin/sozo/src/commands/execute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 87d418789d..741350bdfe 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -48,7 +48,7 @@ pub struct CallArgs { pub calldata: Option, } -+impl std::str::FromStr for CallArgs { +impl std::str::FromStr for CallArgs { type Err = anyhow::Error; From ef4eee59af1bcaa463659d98bd4d23a48bf5d072 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Mon, 11 Nov 2024 11:14:04 +0530 Subject: [PATCH 09/25] Dummy commit --- bin/sozo/src/commands/execute.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 741350bdfe..61a961a96d 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -10,7 +10,6 @@ use sozo_walnut::WalnutDebugger; use starknet::core::types::Call; use starknet::core::utils as snutils; use tracing::trace; - use super::options::account::AccountOptions; use super::options::starknet::StarknetOptions; use super::options::transaction::TransactionOptions; From 6e4a960733b334751e10e0ed51634308f63f9499 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Mon, 11 Nov 2024 11:39:16 +0530 Subject: [PATCH 10/25] Merge conflict solved commit --- bin/sozo/src/commands/execute.rs | 71 +++++++++++++++----------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 61a961a96d..0d6922fb5f 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -3,6 +3,7 @@ use clap::Args; use std::str::FromStr; use dojo_types::naming; use dojo_utils::{Invoker, TxnConfig}; +use dojo_world::config::calldata_decoder; use scarb::core::Config; use sozo_ops::resource_descriptor::ResourceDescriptor; use sozo_scarbext::WorkspaceExt; @@ -14,63 +15,66 @@ use super::options::account::AccountOptions; use super::options::starknet::StarknetOptions; use super::options::transaction::TransactionOptions; use super::options::world::WorldOptions; -use crate::commands::calldata_decoder; use crate::utils; #[derive(Debug, Args)] #[command(about = "Execute a system with the given calldata.")] pub struct ExecuteArgs { - #[arg( - help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" + help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" )] + pub calls: Vec, - pub calls: Vec, + #[arg(long)] + #[arg(help = "If true, sozo will compute the diff of the world from the chain to translate \ + tags to addresses.")] + pub diff: bool, #[command(flatten)] - pub starknet: StarknetOptions, + pub starknet: StarknetOptions, #[command(flatten)] pub account: AccountOptions, #[command(flatten)] - pub world: WorldOptions, + pub world: WorldOptions, #[command(flatten)] - pub transaction: TransactionOptions, + pub transaction: TransactionOptions, } #[derive(Debug)] pub struct CallArgs { - pub tag_or_address: ResourceDescriptor, - pub entrypoint: String, - pub calldata: Option, + pub tag_or_address: ResourceDescriptor, // Contract address or tag + pub entrypoint: String, // Entrypoint to call + pub calldata: Option, // Calldata to pass to the entrypoint } -impl std::str::FromStr for CallArgs { +impl std::str::FromStr for CallArgs { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let s = s.trim(); - if s.is_empty() { - return Err(anyhow!("Empty call string")); - } - + if s.is_empty() { + return Err(anyhow!("Empty call string")); + } + let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { return Err(anyhow!("Invalid call format. Expected format: ,,,,...")); } + let entrypoint = parts[1].trim(); - if entrypoint.is_empty() { - return Err(anyhow!("Empty entrypoint")); - } - if !entrypoint.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { - return Err(anyhow!("Invalid entrypoint format. Must contain only alphanumeric characters and underscores")); - } + if entrypoint.is_empty() { + return Err(anyhow!("Empty entrypoint")); + } + if !entrypoint.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { + return Err(anyhow!("Invalid entrypoint format. Must contain only alphanumeric characters and underscores")); + } Ok(CallArgs { - tag_or_address: parts[0].parse()?, + tag_or_address: parts[0].parse()?, entrypoint: entrypoint.to_string(), calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, }) @@ -95,7 +99,6 @@ fn resolve_contract_address( } } - impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { trace!(args = ?self); @@ -104,19 +107,16 @@ impl ExecuteArgs { let profile_config = ws.load_profile_config()?; - let descriptor = self.tag_or_address.ensure_namespace(&profile_config.namespace.default); - #[cfg(feature = "walnut")] let _walnut_debugger = WalnutDebugger::new_from_flag( self.transaction.walnut, self.starknet.url(profile_config.env.as_ref())?, ); - let txn_config: TxnConfig = self.transaction.into(); + let txn_config: TxnConfig = self.transaction.try_into()?; // Changed from `into()` to `try_into()` for better error handling config.tokio_handle().block_on(async { - // We could save the world diff computation extracting the account directly from the - // options. + // We could save the world diff computation extracting the account directly from the options. let (world_diff, account, _) = utils::get_world_diff_and_account( self.account, self.starknet.clone(), @@ -128,14 +128,14 @@ impl ExecuteArgs { let mut invoker = Invoker::new(&account, txn_config); + // Parse the Vec into Vec using FromStr let call_args_list: Vec = self.calls.iter() - .map(|s| CallArgs::from_string(s)) + .map(|s| s.parse()) .collect::>>()?; for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); - // Checking the contract tag in local manifest let contract_address = if let Some(local_address) = ws.get_contract_address(&descriptor) { local_address @@ -162,15 +162,12 @@ impl ExecuteArgs { selector: snutils::get_selector_from_name(&call_args.entrypoint)?, }; - invoker.add_call(call); - - + invoker.add_call(call); // Adding each call to the Invoker } - let tx_result = invoker.invoke().await?; + + let tx_result = invoker.invoke().await?; // Invoking the multi-call println!("{}", tx_result); Ok(()) - - }) } -} +} \ No newline at end of file From 9a4eeb9c6060dce781c2d0313af9bc9a05fd9010 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Tue, 12 Nov 2024 09:13:11 +0530 Subject: [PATCH 11/25] Getting contracts the right way and also letting string pass if there are empty call args --- bin/sozo/src/commands/execute.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 0d6922fb5f..d950e94c49 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -56,9 +56,7 @@ impl std::str::FromStr for CallArgs { fn from_str(s: &str) -> Result { let s = s.trim(); - if s.is_empty() { - return Err(anyhow!("Empty call string")); - } + let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { @@ -88,10 +86,16 @@ fn resolve_contract_address( match descriptor { ResourceDescriptor::Address(address) => Ok(*address), ResourceDescriptor::Tag(tag) => { - let selector = naming::compute_selector_from_tag(tag); - world_diff - .get_contract_address(selector) - .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff.")) + let contracts = utils::contracts_from_manifest_or_diff( + self.account.clone(), + self.starknet.clone(), + self.world, + &ws, + self.diff, + ) + .await?; + + (contracts.get(tag).map(|c| c.address), contracts) } ResourceDescriptor::Name(_) => { unimplemented!("Expected to be a resolved tag with default namespace.") @@ -113,7 +117,7 @@ impl ExecuteArgs { self.starknet.url(profile_config.env.as_ref())?, ); - let txn_config: TxnConfig = self.transaction.try_into()?; // Changed from `into()` to `try_into()` for better error handling + let txn_config: TxnConfig = self.transaction.try_into()?; config.tokio_handle().block_on(async { // We could save the world diff computation extracting the account directly from the options. From 0363f73b6b152914371692e5cf463ed849f745e4 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 3 Nov 2024 15:18:35 +0530 Subject: [PATCH 12/25] Update execute.rs Added multi-call support to sozo exceute command --- bin/sozo/src/commands/execute.rs | 129 +++++++++++++++++-------------- 1 file changed, 69 insertions(+), 60 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index c8510d1d16..97d55d1132 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -19,6 +19,27 @@ use crate::utils; #[derive(Debug, Args)] #[command(about = "Execute a system with the given calldata.")] pub struct ExecuteArgs { + + #[arg( + help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." + )] + + pub calls: Vec, + + #[command(flatten)] + pub starknet: StarknetOptions, + + #[command(flatten)] + pub account: AccountOptions, + + #[command(flatten)] + pub world: WorldOptions, + + #[command(flatten)] + pub transaction: TransactionOptions, +} + +pub struct CallArgs { #[arg( help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." )] @@ -75,67 +96,55 @@ impl ExecuteArgs { let txn_config: TxnConfig = self.transaction.try_into()?; config.tokio_handle().block_on(async { - let (contract_address, contracts) = match &descriptor { - ResourceDescriptor::Address(address) => (Some(*address), Default::default()), - ResourceDescriptor::Tag(tag) => { - let contracts = utils::contracts_from_manifest_or_diff( - self.account.clone(), - self.starknet.clone(), - self.world, - &ws, - self.diff, - ) - .await?; - - (contracts.get(tag).map(|c| c.address), contracts) - } - ResourceDescriptor::Name(_) => { - unimplemented!("Expected to be a resolved tag with default namespace.") - } - }; - - let contract_address = contract_address.ok_or_else(|| { - let mut message = format!("Contract {descriptor} not found in the manifest."); - if self.diff { - message.push_str( - " Run the command again with `--diff` to force the fetch of data from the \ - chain.", - ); + // We could save the world diff computation extracting the account directly from the + // options. + let (world_diff, account, _) = utils::get_world_diff_and_account( + self.account, + self.starknet.clone(), + self.world, + &ws, + &mut None, + ) + .await?; + + for call_args in self.calls { + let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); + + let contract_address = match &descriptor { + ResourceDescriptor::Address(address) => Some(*address), + ResourceDescriptor::Tag(tag) => { + let selector = naming::compute_selector_from_tag(tag); + world_diff.get_contract_address(selector) + } + ResourceDescriptor::Name(_) => { + unimplemented!("Expected to be a resolved tag with default namespace.") + } } - anyhow!(message) - })?; - - trace!( - contract=?descriptor, - entrypoint=self.entrypoint, - calldata=?self.calldata, - "Executing Execute command." - ); - - let calldata = if let Some(cd) = self.calldata { - calldata_decoder::decode_calldata(&cd)? - } else { - vec![] - }; - - let call = Call { - calldata, - to: contract_address, - selector: snutils::get_selector_from_name(&self.entrypoint)?, - }; - - let (provider, _) = self.starknet.provider(profile_config.env.as_ref())?; - - let account = self - .account - .account(provider, profile_config.env.as_ref(), &self.starknet, &contracts) - .await?; - - let invoker = Invoker::new(&account, txn_config); - // TODO: add walnut back, perhaps at the invoker level. - let tx_result = invoker.invoke(call).await?; - - println!("{}", tx_result); + .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff."))?; + + trace!( + contract=?descriptor, + entrypoint=call_args.entrypoint, + calldata=?call_args.calldata, + "Executing Execute command." + ); + + let calldata = if let Some(cd) = call_args.calldata { + calldata_decoder::decode_calldata(&cd)? + } else { + vec![] + }; + let call = Call { + calldata, + to: contract_address, + selector: snutils::get_selector_from_name(&call_args.entrypoint)?, + }; + + let invoker = Invoker::new(&account, txn_config); + let tx_result = invoker.invoke(call).await?; + + println!("{}", tx_result); + } Ok(()) }) } From 1c9a191ab58e2cc0a1d54e3bc41faf27a89164ab Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 3 Nov 2024 16:57:55 +0530 Subject: [PATCH 13/25] Few minor changes --- bin/sozo/src/commands/execute.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 97d55d1132..43767033a5 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -24,7 +24,7 @@ pub struct ExecuteArgs { help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." )] - pub calls: Vec, + pub calls: Vec, #[command(flatten)] pub starknet: StarknetOptions, @@ -39,6 +39,7 @@ pub struct ExecuteArgs { pub transaction: TransactionOptions, } +#[derive(Debug, Args)] pub struct CallArgs { #[arg( help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." From 7a10e6c40cd205fa81e1d32bce39448a47062200 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Mon, 4 Nov 2024 08:58:02 +0530 Subject: [PATCH 14/25] Keeping vec string --- bin/sozo/src/commands/execute.rs | 84 +++++++++++++++++--------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 43767033a5..98cebf1d7f 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -24,7 +24,7 @@ pub struct ExecuteArgs { help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." )] - pub calls: Vec, + pub calls: Vec, #[command(flatten)] pub starknet: StarknetOptions, @@ -39,43 +39,42 @@ pub struct ExecuteArgs { pub transaction: TransactionOptions, } -#[derive(Debug, Args)] -pub struct CallArgs { - #[arg( - help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." - )] - pub tag_or_address: ResourceDescriptor, - - #[arg(help = "The name of the entrypoint to be executed.")] - pub entrypoint: String, - - #[arg(short, long)] - #[arg(help = "The calldata to be passed to the system. Comma separated values e.g., \ - 0x12345,128,u256:9999999999. Sozo supports some prefixes that you can use to \ - automatically parse some types. The supported prefixes are: - - u256: A 256-bit unsigned integer. - - sstr: A cairo short string. - - str: A cairo string (ByteArray). - - int: A signed integer. - - no prefix: A cairo felt or any type that fit into one felt.")] - pub calldata: Option, - - #[arg(long)] - #[arg(help = "If true, sozo will compute the diff of the world from the chain to translate \ - tags to addresses.")] - pub diff: bool, - - #[command(flatten)] - pub starknet: StarknetOptions, - - #[command(flatten)] - pub account: AccountOptions, - - #[command(flatten)] - pub world: WorldOptions, - - #[command(flatten)] - pub transaction: TransactionOptions, +// #[derive(Debug, Args)] +// pub struct CallArgs { +// #[arg( +// help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." +// )] +// pub tag_or_address: ResourceDescriptor, + +// #[arg(help = "The name of the entrypoint to be executed.")] +// pub entrypoint: String, + +// #[arg(short, long)] +// #[arg(help = "The calldata to be passed to the system. Comma separated values e.g., \ +// 0x12345,128,u256:9999999999. Sozo supports some prefixes that you can use to \ +// automatically parse some types. The supported prefixes are: +// - u256: A 256-bit unsigned integer. +// - sstr: A cairo short string. +// - str: A cairo string (ByteArray). +// - int: A signed integer. +// - no prefix: A cairo felt or any type that fit into one felt.")] +// pub calldata: Option, +// } + + +impl CallArgs { + fn from_string(s: &str) -> Result { + let parts: Vec<&str> = s.split(',').collect(); + if parts.len() < 2 { + return Err(anyhow!("Invalid call format")); + } + + Ok(CallArgs { + tag_or_address: parts[0].parse()?, + entrypoint: parts[1].to_string(), + calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, + }) + } } impl ExecuteArgs { @@ -108,7 +107,11 @@ impl ExecuteArgs { ) .await?; - for call_args in self.calls { + let call_args_list: Vec = self.calls.iter() + .map(|s| CallArgs::from_string(s)) + .collect::>>()?; + + for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); let contract_address = match &descriptor { @@ -135,6 +138,7 @@ impl ExecuteArgs { } else { vec![] }; + let call = Call { calldata, to: contract_address, @@ -147,6 +151,8 @@ impl ExecuteArgs { println!("{}", tx_result); } Ok(()) + + }) } } From 58c5560a1a5c8930d53d935443e85722d86be27f Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Wed, 6 Nov 2024 10:30:25 +0530 Subject: [PATCH 15/25] Sperating each call using commas --- bin/sozo/src/commands/execute.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 98cebf1d7f..ce93a906da 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -61,6 +61,12 @@ pub struct ExecuteArgs { // pub calldata: Option, // } +#[derive(Debug)] +pub struct CallArgs { + pub tag_or_address: ResourceDescriptor, + pub entrypoint: String, + pub calldata: Option, +} impl CallArgs { fn from_string(s: &str) -> Result { @@ -70,13 +76,29 @@ impl CallArgs { } Ok(CallArgs { - tag_or_address: parts[0].parse()?, + tag_or_address: parts[0].parse()?, entrypoint: parts[1].to_string(), calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, }) } } + +// impl CallArgs { +// fn from_string(s: &str) -> Result { +// let parts: Vec<&str> = s.split(',').collect(); +// if parts.len() < 2 { +// return Err(anyhow!("Invalid call format")); +// } + +// Ok(CallArgs { +// tag_or_address: parts[0].parse()?, +// entrypoint: parts[1].to_string(), +// calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, +// }) +// } +// } + impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { trace!(args = ?self); From 9dbf346a986fbb13adac9073c7a233c7aa558262 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Fri, 8 Nov 2024 15:34:50 +0530 Subject: [PATCH 16/25] Implementing Invoker before for loop and creating sep function for contract address --- bin/sozo/src/commands/execute.rs | 78 +++++++++++--------------------- 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index ce93a906da..1c8a34989d 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -21,7 +21,7 @@ use crate::utils; pub struct ExecuteArgs { #[arg( - help = "The calls to be executed. Each call should include the address or tag, entrypoint, and calldata." + help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." )] pub calls: Vec, @@ -39,28 +39,6 @@ pub struct ExecuteArgs { pub transaction: TransactionOptions, } -// #[derive(Debug, Args)] -// pub struct CallArgs { -// #[arg( -// help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." -// )] -// pub tag_or_address: ResourceDescriptor, - -// #[arg(help = "The name of the entrypoint to be executed.")] -// pub entrypoint: String, - -// #[arg(short, long)] -// #[arg(help = "The calldata to be passed to the system. Comma separated values e.g., \ -// 0x12345,128,u256:9999999999. Sozo supports some prefixes that you can use to \ -// automatically parse some types. The supported prefixes are: -// - u256: A 256-bit unsigned integer. -// - sstr: A cairo short string. -// - str: A cairo string (ByteArray). -// - int: A signed integer. -// - no prefix: A cairo felt or any type that fit into one felt.")] -// pub calldata: Option, -// } - #[derive(Debug)] pub struct CallArgs { pub tag_or_address: ResourceDescriptor, @@ -72,7 +50,7 @@ impl CallArgs { fn from_string(s: &str) -> Result { let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { - return Err(anyhow!("Invalid call format")); + return Err(anyhow!("Invalid call format. Expected format: ,,,,...")); } Ok(CallArgs { @@ -83,21 +61,24 @@ impl CallArgs { } } +fn resolve_contract_address( + descriptor: &ResourceDescriptor, + world_diff: &WorldDiff, +) -> Result
{ + match descriptor { + ResourceDescriptor::Address(address) => Ok(*address), + ResourceDescriptor::Tag(tag) => { + let selector = naming::compute_selector_from_tag(tag); + world_diff + .get_contract_address(selector) + .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff.")) + } + ResourceDescriptor::Name(_) => { + unimplemented!("Expected to be a resolved tag with default namespace.") + } + } +} -// impl CallArgs { -// fn from_string(s: &str) -> Result { -// let parts: Vec<&str> = s.split(',').collect(); -// if parts.len() < 2 { -// return Err(anyhow!("Invalid call format")); -// } - -// Ok(CallArgs { -// tag_or_address: parts[0].parse()?, -// entrypoint: parts[1].to_string(), -// calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, -// }) -// } -// } impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { @@ -129,6 +110,8 @@ impl ExecuteArgs { ) .await?; + let mut invoker = Invoker::new(&account, txn_config); + let call_args_list: Vec = self.calls.iter() .map(|s| CallArgs::from_string(s)) .collect::>>()?; @@ -136,17 +119,7 @@ impl ExecuteArgs { for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); - let contract_address = match &descriptor { - ResourceDescriptor::Address(address) => Some(*address), - ResourceDescriptor::Tag(tag) => { - let selector = naming::compute_selector_from_tag(tag); - world_diff.get_contract_address(selector) - } - ResourceDescriptor::Name(_) => { - unimplemented!("Expected to be a resolved tag with default namespace.") - } - } - .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff."))?; + let contract_address = resolve_contract_address(&descriptor, &world_diff)?; trace!( contract=?descriptor, @@ -167,11 +140,12 @@ impl ExecuteArgs { selector: snutils::get_selector_from_name(&call_args.entrypoint)?, }; - let invoker = Invoker::new(&account, txn_config); - let tx_result = invoker.invoke(call).await?; + invoker.add_call(call); - println!("{}", tx_result); + } + let tx_result = invoker.invoke().await?; + println!("{}", tx_result); Ok(()) From 0bdfc444009826f9c48451e5c446e5847d0d3d9c Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Fri, 8 Nov 2024 15:53:02 +0530 Subject: [PATCH 17/25] Using the Fromstr trait for string operations --- bin/sozo/src/commands/execute.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 1c8a34989d..98e612b75d 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -1,5 +1,7 @@ use anyhow::{anyhow, Result}; use clap::Args; +use std::str::FromStr; +use dojo_types::naming; use dojo_utils::{Invoker, TxnConfig}; use dojo_world::config::calldata_decoder; use scarb::core::Config; @@ -21,7 +23,7 @@ use crate::utils; pub struct ExecuteArgs { #[arg( - help = "The address or the tag (ex: dojo_examples:actions) of the contract to be executed." + help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" )] pub calls: Vec, @@ -46,16 +48,31 @@ pub struct CallArgs { pub calldata: Option, } -impl CallArgs { - fn from_string(s: &str) -> Result { ++impl std::str::FromStr for CallArgs { + + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let s = s.trim(); + if s.is_empty() { + return Err(anyhow!("Empty call string")); + } + let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { return Err(anyhow!("Invalid call format. Expected format: ,,,,...")); } + let entrypoint = parts[1].trim(); + if entrypoint.is_empty() { + return Err(anyhow!("Empty entrypoint")); + } + if !entrypoint.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { + return Err(anyhow!("Invalid entrypoint format. Must contain only alphanumeric characters and underscores")); + } Ok(CallArgs { tag_or_address: parts[0].parse()?, - entrypoint: parts[1].to_string(), + entrypoint: entrypoint.to_string(), calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, }) } From 2264ba100ccd7f43d93fcdeb6587cfa59edab46a Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 10 Nov 2024 10:02:50 +0530 Subject: [PATCH 18/25] Checking local manifest for contract tag --- bin/sozo/src/commands/execute.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 98e612b75d..935c46b06b 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -136,7 +136,13 @@ impl ExecuteArgs { for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); - let contract_address = resolve_contract_address(&descriptor, &world_diff)?; + + // Checking the contract tag in local manifest + let contract_address = if let Some(local_address) = ws.get_contract_address(&descriptor) { + local_address + } else { + resolve_contract_address(&descriptor, &world_diff)? + }; trace!( contract=?descriptor, From b421952f23363614ea971f98dcf94384ccf8c9d0 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Sun, 10 Nov 2024 18:25:59 +0530 Subject: [PATCH 19/25] dummy commit --- bin/sozo/src/commands/execute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index 935c46b06b..a7b07fc324 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -48,7 +48,7 @@ pub struct CallArgs { pub calldata: Option, } -+impl std::str::FromStr for CallArgs { +impl std::str::FromStr for CallArgs { type Err = anyhow::Error; From a3480ffc61439c7bd7bd17e88948e38adf24862c Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Mon, 11 Nov 2024 11:14:04 +0530 Subject: [PATCH 20/25] Dummy commit --- bin/sozo/src/commands/execute.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index a7b07fc324..b7dcd5dfb2 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -11,7 +11,6 @@ use sozo_walnut::WalnutDebugger; use starknet::core::types::Call; use starknet::core::utils as snutils; use tracing::trace; - use super::options::account::AccountOptions; use super::options::starknet::StarknetOptions; use super::options::transaction::TransactionOptions; From a7996a268c7c4c7f88fe4addb17a8d2126bb50c0 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Mon, 11 Nov 2024 11:39:16 +0530 Subject: [PATCH 21/25] Merge conflict solved commit --- bin/sozo/src/commands/execute.rs | 67 +++++++++++++++----------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index b7dcd5dfb2..aa56e60344 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -20,57 +20,61 @@ use crate::utils; #[derive(Debug, Args)] #[command(about = "Execute a system with the given calldata.")] pub struct ExecuteArgs { - #[arg( - help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" + help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" )] + pub calls: Vec, - pub calls: Vec, + #[arg(long)] + #[arg(help = "If true, sozo will compute the diff of the world from the chain to translate \ + tags to addresses.")] + pub diff: bool, #[command(flatten)] - pub starknet: StarknetOptions, + pub starknet: StarknetOptions, #[command(flatten)] pub account: AccountOptions, #[command(flatten)] - pub world: WorldOptions, + pub world: WorldOptions, #[command(flatten)] - pub transaction: TransactionOptions, + pub transaction: TransactionOptions, } #[derive(Debug)] pub struct CallArgs { - pub tag_or_address: ResourceDescriptor, - pub entrypoint: String, - pub calldata: Option, + pub tag_or_address: ResourceDescriptor, // Contract address or tag + pub entrypoint: String, // Entrypoint to call + pub calldata: Option, // Calldata to pass to the entrypoint } -impl std::str::FromStr for CallArgs { +impl std::str::FromStr for CallArgs { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let s = s.trim(); - if s.is_empty() { - return Err(anyhow!("Empty call string")); - } - + if s.is_empty() { + return Err(anyhow!("Empty call string")); + } + let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { return Err(anyhow!("Invalid call format. Expected format: ,,,,...")); } + let entrypoint = parts[1].trim(); - if entrypoint.is_empty() { - return Err(anyhow!("Empty entrypoint")); - } - if !entrypoint.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { - return Err(anyhow!("Invalid entrypoint format. Must contain only alphanumeric characters and underscores")); - } + if entrypoint.is_empty() { + return Err(anyhow!("Empty entrypoint")); + } + if !entrypoint.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') { + return Err(anyhow!("Invalid entrypoint format. Must contain only alphanumeric characters and underscores")); + } Ok(CallArgs { - tag_or_address: parts[0].parse()?, + tag_or_address: parts[0].parse()?, entrypoint: entrypoint.to_string(), calldata: if parts.len() > 2 { Some(parts[2..].join(",")) } else { None }, }) @@ -95,7 +99,6 @@ fn resolve_contract_address( } } - impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { trace!(args = ?self); @@ -104,8 +107,6 @@ impl ExecuteArgs { let profile_config = ws.load_profile_config()?; - let descriptor = self.tag_or_address.ensure_namespace(&profile_config.namespace.default); - #[cfg(feature = "walnut")] let _walnut_debugger = WalnutDebugger::new_from_flag( self.transaction.walnut, @@ -115,8 +116,7 @@ impl ExecuteArgs { let txn_config: TxnConfig = self.transaction.try_into()?; config.tokio_handle().block_on(async { - // We could save the world diff computation extracting the account directly from the - // options. + // We could save the world diff computation extracting the account directly from the options. let (world_diff, account, _) = utils::get_world_diff_and_account( self.account, self.starknet.clone(), @@ -128,14 +128,14 @@ impl ExecuteArgs { let mut invoker = Invoker::new(&account, txn_config); + // Parse the Vec into Vec using FromStr let call_args_list: Vec = self.calls.iter() - .map(|s| CallArgs::from_string(s)) + .map(|s| s.parse()) .collect::>>()?; for call_args in call_args_list { let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); - // Checking the contract tag in local manifest let contract_address = if let Some(local_address) = ws.get_contract_address(&descriptor) { local_address @@ -162,15 +162,12 @@ impl ExecuteArgs { selector: snutils::get_selector_from_name(&call_args.entrypoint)?, }; - invoker.add_call(call); - - + invoker.add_call(call); // Adding each call to the Invoker } - let tx_result = invoker.invoke().await?; + + let tx_result = invoker.invoke().await?; // Invoking the multi-call println!("{}", tx_result); Ok(()) - - }) } -} +} \ No newline at end of file From 0f742d6bfdba30e7f8f97958ca9a8b4568ce4c30 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Tue, 12 Nov 2024 09:13:11 +0530 Subject: [PATCH 22/25] Getting contracts the right way and also letting string pass if there are empty call args --- bin/sozo/src/commands/execute.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index aa56e60344..d950e94c49 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -56,9 +56,7 @@ impl std::str::FromStr for CallArgs { fn from_str(s: &str) -> Result { let s = s.trim(); - if s.is_empty() { - return Err(anyhow!("Empty call string")); - } + let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { @@ -88,10 +86,16 @@ fn resolve_contract_address( match descriptor { ResourceDescriptor::Address(address) => Ok(*address), ResourceDescriptor::Tag(tag) => { - let selector = naming::compute_selector_from_tag(tag); - world_diff - .get_contract_address(selector) - .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff.")) + let contracts = utils::contracts_from_manifest_or_diff( + self.account.clone(), + self.starknet.clone(), + self.world, + &ws, + self.diff, + ) + .await?; + + (contracts.get(tag).map(|c| c.address), contracts) } ResourceDescriptor::Name(_) => { unimplemented!("Expected to be a resolved tag with default namespace.") @@ -113,7 +117,7 @@ impl ExecuteArgs { self.starknet.url(profile_config.env.as_ref())?, ); - let txn_config: TxnConfig = self.transaction.try_into()?; + let txn_config: TxnConfig = self.transaction.try_into()?; config.tokio_handle().block_on(async { // We could save the world diff computation extracting the account directly from the options. From 970e489740e995897ba1c2c9cc02523da0c5b9f0 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Tue, 12 Nov 2024 09:34:46 +0530 Subject: [PATCH 23/25] Problems of using self in the resolve_contract_address function --- bin/sozo/src/commands/execute.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index d950e94c49..a243488fc8 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -82,16 +82,19 @@ impl std::str::FromStr for CallArgs { fn resolve_contract_address( descriptor: &ResourceDescriptor, world_diff: &WorldDiff, + options: &ExecuteArgs, + ws: &Workspace, ) -> Result
{ match descriptor { ResourceDescriptor::Address(address) => Ok(*address), ResourceDescriptor::Tag(tag) => { let contracts = utils::contracts_from_manifest_or_diff( - self.account.clone(), - self.starknet.clone(), - self.world, + + options.account.clone(), + options.starknet.clone(), + options.world, &ws, - self.diff, + options.diff, ) .await?; From e25f6c7b7ce6eeba062ce3c11848ea0ccdc883b2 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Wed, 13 Nov 2024 09:22:26 +0530 Subject: [PATCH 24/25] Fmt and also fixed some errors --- bin/sozo/src/commands/execute.rs | 69 +++++++++++++++++--------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index a243488fc8..da9d5a9cbe 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -1,7 +1,10 @@ +use super::options::account::AccountOptions; +use super::options::starknet::StarknetOptions; +use super::options::transaction::TransactionOptions; +use super::options::world::WorldOptions; +use crate::utils; use anyhow::{anyhow, Result}; use clap::Args; -use std::str::FromStr; -use dojo_types::naming; use dojo_utils::{Invoker, TxnConfig}; use dojo_world::config::calldata_decoder; use scarb::core::Config; @@ -10,12 +13,11 @@ use sozo_scarbext::WorkspaceExt; use sozo_walnut::WalnutDebugger; use starknet::core::types::Call; use starknet::core::utils as snutils; + +use dojo_world::diff::WorldDiff; +use scarb::core::Workspace; +use starknet::core::types::Address; use tracing::trace; -use super::options::account::AccountOptions; -use super::options::starknet::StarknetOptions; -use super::options::transaction::TransactionOptions; -use super::options::world::WorldOptions; -use crate::utils; #[derive(Debug, Args)] #[command(about = "Execute a system with the given calldata.")] @@ -23,40 +25,38 @@ pub struct ExecuteArgs { #[arg( help = "List of calls to execute. Each call should be in format: ,,,,... (ex: dojo_examples:actions,execute,1,2)" )] - pub calls: Vec, + pub calls: Vec, #[arg(long)] #[arg(help = "If true, sozo will compute the diff of the world from the chain to translate \ tags to addresses.")] - pub diff: bool, + pub diff: bool, #[command(flatten)] - pub starknet: StarknetOptions, + pub starknet: StarknetOptions, #[command(flatten)] pub account: AccountOptions, #[command(flatten)] - pub world: WorldOptions, + pub world: WorldOptions, #[command(flatten)] - pub transaction: TransactionOptions, + pub transaction: TransactionOptions, } #[derive(Debug)] pub struct CallArgs { pub tag_or_address: ResourceDescriptor, // Contract address or tag - pub entrypoint: String, // Entrypoint to call - pub calldata: Option, // Calldata to pass to the entrypoint + pub entrypoint: String, // Entrypoint to call + pub calldata: Option, // Calldata to pass to the entrypoint } - impl std::str::FromStr for CallArgs { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let s = s.trim(); - let parts: Vec<&str> = s.split(',').collect(); if parts.len() < 2 { @@ -79,7 +79,7 @@ impl std::str::FromStr for CallArgs { } } -fn resolve_contract_address( +async fn resolve_contract_address( descriptor: &ResourceDescriptor, world_diff: &WorldDiff, options: &ExecuteArgs, @@ -89,16 +89,18 @@ fn resolve_contract_address( ResourceDescriptor::Address(address) => Ok(*address), ResourceDescriptor::Tag(tag) => { let contracts = utils::contracts_from_manifest_or_diff( - options.account.clone(), - options.starknet.clone(), - options.world, + options.starknet.clone(), + options.world, &ws, options.diff, ) .await?; - (contracts.get(tag).map(|c| c.address), contracts) + contracts + .get(tag) + .map(|c| c.address) + .ok_or_else(|| anyhow!("Contract {descriptor} not found in the world diff.")) } ResourceDescriptor::Name(_) => { unimplemented!("Expected to be a resolved tag with default namespace.") @@ -120,7 +122,7 @@ impl ExecuteArgs { self.starknet.url(profile_config.env.as_ref())?, ); - let txn_config: TxnConfig = self.transaction.try_into()?; + let txn_config: TxnConfig = self.transaction.try_into()?; config.tokio_handle().block_on(async { // We could save the world diff computation extracting the account directly from the options. @@ -136,19 +138,20 @@ impl ExecuteArgs { let mut invoker = Invoker::new(&account, txn_config); // Parse the Vec into Vec using FromStr - let call_args_list: Vec = self.calls.iter() - .map(|s| s.parse()) - .collect::>>()?; + let call_args_list: Vec = + self.calls.iter().map(|s| s.parse()).collect::>>()?; for call_args in call_args_list { - let descriptor = call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); + let descriptor = + call_args.tag_or_address.ensure_namespace(&profile_config.namespace.default); // Checking the contract tag in local manifest - let contract_address = if let Some(local_address) = ws.get_contract_address(&descriptor) { - local_address - } else { - resolve_contract_address(&descriptor, &world_diff)? - }; + let contract_address = + if let Some(local_address) = ws.get_contract_address(&descriptor) { + local_address + } else { + resolve_contract_address(&descriptor, &self, &ws).await?; + }; trace!( contract=?descriptor, @@ -172,9 +175,9 @@ impl ExecuteArgs { invoker.add_call(call); // Adding each call to the Invoker } - let tx_result = invoker.invoke().await?; // Invoking the multi-call + let tx_result = invoker.invoke(call).await?; // Invoking the multi-call println!("{}", tx_result); Ok(()) }) } -} \ No newline at end of file +} From 608bd9f7d86566dd1059d07285be94dfb8393863 Mon Sep 17 00:00:00 2001 From: Manush Sanchela Date: Wed, 13 Nov 2024 10:02:07 +0530 Subject: [PATCH 25/25] Some final changes --- bin/sozo/src/commands/execute.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/sozo/src/commands/execute.rs b/bin/sozo/src/commands/execute.rs index da9d5a9cbe..0305fa2186 100644 --- a/bin/sozo/src/commands/execute.rs +++ b/bin/sozo/src/commands/execute.rs @@ -150,7 +150,7 @@ impl ExecuteArgs { if let Some(local_address) = ws.get_contract_address(&descriptor) { local_address } else { - resolve_contract_address(&descriptor, &self, &ws).await?; + resolve_contract_address(&descriptor, &world_diff, &ws).await?; }; trace!(