From b697201dfb08224ff65b2e66828e3088d9976bf2 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 25 Nov 2024 11:47:24 +0100 Subject: [PATCH 01/15] feat: submit extrinsic from call_data --- crates/pop-cli/src/commands/call/parachain.rs | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index db0e7c41..cfd6da09 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -91,8 +91,9 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call || - !cli.confirm("Do you want to perform another call?") + if !prompt_to_repeat_call + || !cli + .confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -155,8 +156,9 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, + Some(ref extrinsic_name) => { + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? + }, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -193,8 +195,9 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, + None => { + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? + }, }; return Ok(CallParachain { @@ -220,8 +223,9 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -255,11 +259,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() || - self.extrinsic.is_none() || - self.args.is_empty() || - self.url.is_none() || - self.suri.is_none() + self.pallet.is_none() + || self.extrinsic.is_none() + || self.args.is_empty() + || self.url.is_none() + || self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -342,8 +346,9 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -402,6 +407,7 @@ async fn prompt_predefined_actions( pallets: &[Pallet], cli: &mut impl Cli, ) -> Result> { + println!("1 select"); let mut predefined_action = cli.select("What would you like to do?"); for action in supported_actions(pallets).await { predefined_action = predefined_action.item( From edfe5d963c80546c843a5fa23ca14ac638e44333 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Thu, 28 Nov 2024 18:04:39 +0100 Subject: [PATCH 02/15] test: unit test for initialize_api_client --- crates/pop-cli/src/commands/call/parachain.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index cfd6da09..29199b02 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -407,7 +407,6 @@ async fn prompt_predefined_actions( pallets: &[Pallet], cli: &mut impl Cli, ) -> Result> { - println!("1 select"); let mut predefined_action = cli.select("What would you like to do?"); for action in supported_actions(pallets).await { predefined_action = predefined_action.item( From 64397bc7c2781b7f24f4ce19394ee30721867ab4 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 25 Nov 2024 12:00:44 +0100 Subject: [PATCH 03/15] feat: wrap call into a sudo call --- crates/pop-cli/src/commands/call/parachain.rs | 34 ++++++++++++++++--- crates/pop-parachains/src/call/mod.rs | 8 +++++ crates/pop-parachains/src/lib.rs | 2 +- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 29199b02..4b2a51b2 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -6,10 +6,10 @@ use crate::cli::{self, traits::*}; use anyhow::{anyhow, Result}; use clap::Args; use pop_parachains::{ - construct_extrinsic, decode_call_data, encode_call_data, find_extrinsic_by_name, - find_pallet_by_name, parse_chain_metadata, set_up_client, sign_and_submit_extrinsic, - sign_and_submit_extrinsic_with_call_data, supported_actions, Action, DynamicPayload, Extrinsic, - OnlineClient, Pallet, Param, SubstrateConfig, + construct_extrinsic, construct_sudo_extrinsic, decode_call_data, encode_call_data, + find_extrinsic_by_name, find_pallet_by_name, parse_chain_metadata, set_up_client, + sign_and_submit_extrinsic, sign_and_submit_extrinsic_with_call_data, supported_actions, Action, + DynamicPayload, Extrinsic, OnlineClient, Pallet, Param, SubstrateConfig, }; use url::Url; @@ -42,6 +42,9 @@ pub struct CallParachainCommand { /// SCALE encoded bytes representing the call data of the extrinsic. #[arg(name = "call", long, conflicts_with_all = ["pallet", "extrinsic", "args"])] call_data: Option, + /// Authenticates the sudo key and dispatches a function call with `Root` origin. + #[arg(name = "sudo", long, short = 'S')] + sudo: bool, /// Automatically signs and submits the extrinsic without prompting for confirmation. #[arg(short('y'), long)] skip_confirm: bool, @@ -192,6 +195,14 @@ impl CallParachainCommand { self.expand_file_arguments()? }; + // Prompt the user to confirm if they want to execute the call with sudo privileges. + if !self.sudo { + self.sudo = cli + .confirm("Would you like to execute this operation with sudo privileges?") + .initial_value(false) + .interact()?; + } + // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), @@ -206,6 +217,7 @@ impl CallParachainCommand { args, suri, skip_confirm: self.skip_confirm, + sudo: self.sudo, }); } } @@ -255,6 +267,7 @@ impl CallParachainCommand { self.pallet = None; self.extrinsic = None; self.args.clear(); + self.sudo = false; } // Function to check if all required fields are specified. @@ -310,6 +323,8 @@ struct CallParachain { suri: String, /// Whether to automatically sign and submit the extrinsic without prompting for confirmation. skip_confirm: bool, + /// Whether to dispatch the function call with `Root` origin. + sudo: bool, } impl CallParachain { @@ -331,6 +346,8 @@ impl CallParachain { return Err(anyhow!("Error: {}", e)); }, }; + // If sudo is enabled, wrap the call in a sudo call. + let tx = if self.sudo { construct_sudo_extrinsic(tx).await? } else { tx }; let encoded_data = encode_call_data(client, &tx)?; // If the encoded call data is too long, don't display it all. if encoded_data.len() < ENCODED_CALL_DATA_MAX_LEN { @@ -388,6 +405,9 @@ impl CallParachain { full_message.push_str(&format!(" --args {}", args.join(" "))); } full_message.push_str(&format!(" --url {} --suri {}", chain.url, self.suri)); + if self.sudo { + full_message.push_str(" --sudo"); + } full_message } } @@ -686,6 +706,7 @@ mod tests { args: vec!["0x11".to_string()].to_vec(), suri: DEFAULT_URI.to_string(), skip_confirm: false, + sudo: false, }; let mut cli = MockCli::new(); // Error, wrong name of the pallet. @@ -718,6 +739,7 @@ mod tests { args: vec!["0x11".to_string()].to_vec(), suri: DEFAULT_URI.to_string(), skip_confirm: false, + sudo: false, }; let mut cli = MockCli::new() .expect_confirm("Do you want to submit the extrinsic?", false) @@ -739,6 +761,7 @@ mod tests { suri: None, skip_confirm: false, call_data: Some("0x00000411".to_string()), + sudo: false, }; let mut cli = MockCli::new() .expect_input("Signer of the extrinsic:", "//Bob".into()) @@ -761,6 +784,7 @@ mod tests { suri: Some(DEFAULT_URI.to_string()), skip_confirm: false, call_data: None, + sudo: true, }; call_config.reset_for_new_call(); assert_eq!(call_config.pallet, None); @@ -779,6 +803,7 @@ mod tests { suri: Some(DEFAULT_URI.to_string()), skip_confirm: false, call_data: None, + sudo: false, }; assert!(!call_config.requires_user_input()); call_config.pallet = None; @@ -796,6 +821,7 @@ mod tests { suri: Some(DEFAULT_URI.to_string()), skip_confirm: false, call_data: None, + sudo: false, }; assert_eq!( call_config.expand_file_arguments()?, diff --git a/crates/pop-parachains/src/call/mod.rs b/crates/pop-parachains/src/call/mod.rs index 136d0d2d..ea1ee12a 100644 --- a/crates/pop-parachains/src/call/mod.rs +++ b/crates/pop-parachains/src/call/mod.rs @@ -36,6 +36,14 @@ pub async fn construct_extrinsic( Ok(subxt::dynamic::tx(pallet_name, extrinsic.name.clone(), parsed_args)) } +/// Constructs a Sudo extrinsic. +/// +/// # Arguments +/// * `tx`: The transaction to be executed with sudo privileges. +pub async fn construct_sudo_extrinsic(tx: DynamicPayload) -> Result { + Ok(subxt::dynamic::tx("Sudo", "sudo", [tx.into_value()].to_vec())) +} + /// Signs and submits a given extrinsic. /// /// # Arguments diff --git a/crates/pop-parachains/src/lib.rs b/crates/pop-parachains/src/lib.rs index 00f24975..b2bbfa64 100644 --- a/crates/pop-parachains/src/lib.rs +++ b/crates/pop-parachains/src/lib.rs @@ -17,7 +17,7 @@ pub use build::{ generate_plain_chain_spec, generate_raw_chain_spec, is_supported, ChainSpec, }; pub use call::{ - construct_extrinsic, decode_call_data, encode_call_data, + construct_extrinsic, construct_sudo_extrinsic, decode_call_data, encode_call_data, metadata::{ action::{supported_actions, Action}, find_extrinsic_by_name, find_pallet_by_name, From 279b38ea1bd393f5b0a379cca61c0c76a0bc7cb9 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Fri, 29 Nov 2024 12:18:54 +0100 Subject: [PATCH 04/15] test: add unit test to the new logic --- crates/pop-cli/src/commands/call/parachain.rs | 21 +++++++++++++------ crates/pop-parachains/src/call/mod.rs | 17 +++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 4b2a51b2..53d1c823 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -43,7 +43,7 @@ pub struct CallParachainCommand { #[arg(name = "call", long, conflicts_with_all = ["pallet", "extrinsic", "args"])] call_data: Option, /// Authenticates the sudo key and dispatches a function call with `Root` origin. - #[arg(name = "sudo", long, short = 'S')] + #[arg(name = "sudo", short = 'S', long)] sudo: bool, /// Automatically signs and submits the extrinsic without prompting for confirmation. #[arg(short('y'), long)] @@ -637,7 +637,8 @@ mod tests { 0, // "remark" extrinsic ) .expect_input("The value for `remark` might be too large to enter. You may enter the path to a file instead.", "0x11".into()) - .expect_input("Signer of the extrinsic:", BOB_SURI.into()); + .expect_confirm("Would you like to execute this operation with sudo privileges?", true) + .expect_input("Signer of the extrinsic:", "//Bob".into()); let chain = call_config.configure_chain(&mut cli).await?; assert_eq!(chain.url, Url::parse(POP_NETWORK_TESTNET_URL)?); @@ -646,8 +647,9 @@ mod tests { assert_eq!(call_parachain.pallet.name, "System"); assert_eq!(call_parachain.extrinsic.name, "remark"); assert_eq!(call_parachain.args, ["0x11".to_string()].to_vec()); - assert_eq!(call_parachain.suri, BOB_SURI); - assert_eq!(call_parachain.display(&chain), format!("pop call parachain --pallet System --extrinsic remark --args \"0x11\" --url {}/ --suri {}", POP_NETWORK_TESTNET_URL, BOB_SURI)); + assert_eq!(call_parachain.suri, "//Bob"); + assert!(call_parachain.sudo); + assert_eq!(call_parachain.display(&chain), "pop call parachain --pallet System --extrinsic remark --args \"0x11\" --url wss://rpc1.paseo.popnetwork.xyz/ --suri //Bob --sudo"); cli.verify() } @@ -692,8 +694,9 @@ mod tests { assert_eq!(call_parachain.pallet.name, "OnDemand"); assert_eq!(call_parachain.extrinsic.name, "place_order_allow_death"); assert_eq!(call_parachain.args, ["10000".to_string(), "2000".to_string()].to_vec()); - assert_eq!(call_parachain.suri, BOB_SURI); - assert_eq!(call_parachain.display(&chain), format!("pop call parachain --pallet OnDemand --extrinsic place_order_allow_death --args \"10000\" \"2000\" --url {}/ --suri {}", POLKADOT_NETWORK_URL, BOB_SURI)); + assert_eq!(call_parachain.suri, "//Bob"); + assert!(!call_config.sudo); + assert_eq!(call_parachain.display(&chain), "pop call parachain --pallet OnDemand --extrinsic place_order_allow_death --args \"10000\" \"2000\" --url wss://polkadot-rpc.publicnode.com/ --suri //Bob"); cli.verify() } @@ -726,6 +729,11 @@ mod tests { assert_eq!(tx.call_name(), "remark"); assert_eq!(tx.pallet_name(), "System"); + // Prepare extrinsic wrapped in sudo works. + cli = MockCli::new().expect_info("Encoded call data: 0x0f0000000411"); + call_config.sudo = true; + call_config.prepare_extrinsic(&client, &mut cli).await?; + cli.verify() } @@ -790,6 +798,7 @@ mod tests { assert_eq!(call_config.pallet, None); assert_eq!(call_config.extrinsic, None); assert_eq!(call_config.args.len(), 0); + assert!(!call_config.sudo); Ok(()) } diff --git a/crates/pop-parachains/src/call/mod.rs b/crates/pop-parachains/src/call/mod.rs index ea1ee12a..cd450d96 100644 --- a/crates/pop-parachains/src/call/mod.rs +++ b/crates/pop-parachains/src/call/mod.rs @@ -223,4 +223,21 @@ mod tests { )); Ok(()) } + + #[tokio::test] + async fn construct_sudo_extrinsic_works() -> Result<()> { + let extrinsic = construct_extrinsic( + "Balances", + "transfer_allow_death", + vec![ + "Id(5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty)".to_string(), + "100".to_string(), + ], + ) + .await?; + let sudo_extrinsic = construct_sudo_extrinsic(extrinsic).await?; + assert_eq!(sudo_extrinsic.call_name(), "sudo"); + assert_eq!(sudo_extrinsic.pallet_name(), "Sudo"); + Ok(()) + } } From 1abad8ac1b1e94d5400afcff11495b99a7287329 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 2 Dec 2024 22:50:06 +0100 Subject: [PATCH 05/15] fix: skip_confirm for send_extrinsic_from_call_data --- crates/pop-cli/src/commands/call/parachain.rs | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 53d1c823..8940b49c 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,9 +94,8 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call - || !cli - .confirm("Do you want to perform another call?") + if !prompt_to_repeat_call || + !cli.confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -159,9 +158,8 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => { - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? - }, + Some(ref extrinsic_name) => + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -206,9 +204,8 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => { - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? - }, + None => + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; return Ok(CallParachain { @@ -235,9 +232,8 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -272,11 +268,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() - || self.extrinsic.is_none() - || self.args.is_empty() - || self.url.is_none() - || self.suri.is_none() + self.pallet.is_none() || + self.extrinsic.is_none() || + self.args.is_empty() || + self.url.is_none() || + self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -363,9 +359,8 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { From 4a31d93ff47dd15c094059f2d9d67afef355d659 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 2 Dec 2024 22:51:19 +0100 Subject: [PATCH 06/15] chore: clippy --- crates/pop-cli/src/commands/call/parachain.rs | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 8940b49c..53d1c823 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,8 +94,9 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call || - !cli.confirm("Do you want to perform another call?") + if !prompt_to_repeat_call + || !cli + .confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -158,8 +159,9 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, + Some(ref extrinsic_name) => { + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? + }, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -204,8 +206,9 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, + None => { + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? + }, }; return Ok(CallParachain { @@ -232,8 +235,9 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -268,11 +272,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() || - self.extrinsic.is_none() || - self.args.is_empty() || - self.url.is_none() || - self.suri.is_none() + self.pallet.is_none() + || self.extrinsic.is_none() + || self.args.is_empty() + || self.url.is_none() + || self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -359,8 +363,9 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { From f4520bf5ecb0a9f0d2a8f47dd7eb9c08b5b6f234 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Thu, 5 Dec 2024 13:50:24 +0100 Subject: [PATCH 07/15] docs: renaming and improve docs --- crates/pop-cli/src/commands/call/parachain.rs | 10 +++++----- crates/pop-parachains/src/call/mod.rs | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 53d1c823..f07ceb53 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -43,7 +43,7 @@ pub struct CallParachainCommand { #[arg(name = "call", long, conflicts_with_all = ["pallet", "extrinsic", "args"])] call_data: Option, /// Authenticates the sudo key and dispatches a function call with `Root` origin. - #[arg(name = "sudo", short = 'S', long)] + #[arg(short = 'S', long)] sudo: bool, /// Automatically signs and submits the extrinsic without prompting for confirmation. #[arg(short('y'), long)] @@ -195,10 +195,10 @@ impl CallParachainCommand { self.expand_file_arguments()? }; - // Prompt the user to confirm if they want to execute the call with sudo privileges. + // Prompt the user to confirm if they want to execute the call via sudo. if !self.sudo { self.sudo = cli - .confirm("Would you like to execute this operation with sudo privileges?") + .confirm("Would you like to dispatch this function call with `Root` origin?") .initial_value(false) .interact()?; } @@ -346,7 +346,7 @@ impl CallParachain { return Err(anyhow!("Error: {}", e)); }, }; - // If sudo is enabled, wrap the call in a sudo call. + // If sudo is required, wrap the call in a sudo call. let tx = if self.sudo { construct_sudo_extrinsic(tx).await? } else { tx }; let encoded_data = encode_call_data(client, &tx)?; // If the encoded call data is too long, don't display it all. @@ -637,7 +637,7 @@ mod tests { 0, // "remark" extrinsic ) .expect_input("The value for `remark` might be too large to enter. You may enter the path to a file instead.", "0x11".into()) - .expect_confirm("Would you like to execute this operation with sudo privileges?", true) + .expect_confirm("Would you like to dispatch this function call with `Root` origin?", true) .expect_input("Signer of the extrinsic:", "//Bob".into()); let chain = call_config.configure_chain(&mut cli).await?; diff --git a/crates/pop-parachains/src/call/mod.rs b/crates/pop-parachains/src/call/mod.rs index cd450d96..bca9785c 100644 --- a/crates/pop-parachains/src/call/mod.rs +++ b/crates/pop-parachains/src/call/mod.rs @@ -39,7 +39,8 @@ pub async fn construct_extrinsic( /// Constructs a Sudo extrinsic. /// /// # Arguments -/// * `tx`: The transaction to be executed with sudo privileges. +/// * `tx`: The transaction payload representing the function call to be dispatched with `Root` +/// privileges. pub async fn construct_sudo_extrinsic(tx: DynamicPayload) -> Result { Ok(subxt::dynamic::tx("Sudo", "sudo", [tx.into_value()].to_vec())) } From 491dc884de82db3ea4a7fc2cb6af179cd61a1a79 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Thu, 5 Dec 2024 13:52:36 +0100 Subject: [PATCH 08/15] test: use force_transfer for testing --- crates/pop-parachains/src/call/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/pop-parachains/src/call/mod.rs b/crates/pop-parachains/src/call/mod.rs index bca9785c..a1828840 100644 --- a/crates/pop-parachains/src/call/mod.rs +++ b/crates/pop-parachains/src/call/mod.rs @@ -229,9 +229,10 @@ mod tests { async fn construct_sudo_extrinsic_works() -> Result<()> { let extrinsic = construct_extrinsic( "Balances", - "transfer_allow_death", + "force_transfer", vec![ "Id(5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty)".to_string(), + "Id(5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy)".to_string(), "100".to_string(), ], ) From 7af028d4f693c12ee6e361263519d24423fec9ae Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Thu, 5 Dec 2024 14:24:17 +0100 Subject: [PATCH 09/15] fix: check if sudo exist before prompt the user --- crates/pop-cli/src/commands/call/parachain.rs | 100 +++++++++++++----- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index f07ceb53..523a144d 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,9 +94,8 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call - || !cli - .confirm("Do you want to perform another call?") + if !prompt_to_repeat_call || + !cli.confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -159,9 +158,8 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => { - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? - }, + Some(ref extrinsic_name) => + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -195,20 +193,15 @@ impl CallParachainCommand { self.expand_file_arguments()? }; - // Prompt the user to confirm if they want to execute the call via sudo. - if !self.sudo { - self.sudo = cli - .confirm("Would you like to dispatch this function call with `Root` origin?") - .initial_value(false) - .interact()?; - } + // If chain has sudo prompt the user to confirm if they want to execute the call via + // sudo. + self.configure_sudo(chain, cli).await?; // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => { - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? - }, + None => + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; return Ok(CallParachain { @@ -235,9 +228,8 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -262,6 +254,28 @@ impl CallParachainCommand { Ok(()) } + // Checks if the chain has the Sudo pallet and prompt the user to confirm if they want to + // execute the call via sudo. + async fn configure_sudo(&mut self, chain: &Chain, cli: &mut impl Cli) -> Result<()> { + match find_extrinsic_by_name(&chain.pallets, "Sudo", "sudo").await { + Ok(_) => + if !self.sudo { + self.sudo = cli + .confirm( + "Would you like to dispatch this function call with `Root` origin?", + ) + .initial_value(false) + .interact()?; + }, + Err(_) => + if self.sudo { + cli.warning("NOTE: sudo extrinsic is not supported by the chain. Ignoring `--sudo` flag.")?; + self.sudo = false; + }, + } + Ok(()) + } + // Resets specific fields to default values for a new call. fn reset_for_new_call(&mut self) { self.pallet = None; @@ -272,11 +286,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() - || self.extrinsic.is_none() - || self.args.is_empty() - || self.url.is_none() - || self.suri.is_none() + self.pallet.is_none() || + self.extrinsic.is_none() || + self.args.is_empty() || + self.url.is_none() || + self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -363,9 +377,8 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -782,6 +795,39 @@ mod tests { cli.verify() } + #[tokio::test] + async fn configure_sudo_works() -> Result<()> { + // Test when sudo pallet doesn't exist. + let mut call_config = CallParachainCommand { + pallet: None, + extrinsic: None, + args: vec![].to_vec(), + url: Some(Url::parse("wss://polkadot-rpc.publicnode.com")?), + suri: Some("//Alice".to_string()), + skip_confirm: false, + call_data: Some("0x00000411".to_string()), + sudo: true, + }; + let mut cli = MockCli::new().expect_intro("Call a parachain").expect_warning( + "NOTE: sudo extrinsic is not supported by the chain. Ignoring `--sudo` flag.", + ); + let chain = call_config.configure_chain(&mut cli).await?; + call_config.configure_sudo(&chain, &mut cli).await?; + assert!(!call_config.sudo); + cli.verify()?; + + // Test when sudo pallet exist. + cli = MockCli::new().expect_intro("Call a parachain").expect_confirm( + "Would you like to dispatch this function call with `Root` origin?", + true, + ); + call_config.url = Some(Url::parse("wss://rpc1.paseo.popnetwork.xyz")?); + let chain = call_config.configure_chain(&mut cli).await?; + call_config.configure_sudo(&chain, &mut cli).await?; + assert!(call_config.sudo); + cli.verify() + } + #[test] fn reset_for_new_call_works() -> Result<()> { let mut call_config = CallParachainCommand { From e24cc22bd1f81e726fa857a5232a751251bc6051 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 9 Dec 2024 08:56:30 +0100 Subject: [PATCH 10/15] chore: fmt --- crates/pop-cli/src/commands/call/parachain.rs | 45 +++++++++++-------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 523a144d..8d5709e8 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,8 +94,9 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call || - !cli.confirm("Do you want to perform another call?") + if !prompt_to_repeat_call + || !cli + .confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -158,8 +159,9 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, + Some(ref extrinsic_name) => { + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? + }, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -200,8 +202,9 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, + None => { + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? + }, }; return Ok(CallParachain { @@ -228,8 +231,9 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -258,7 +262,7 @@ impl CallParachainCommand { // execute the call via sudo. async fn configure_sudo(&mut self, chain: &Chain, cli: &mut impl Cli) -> Result<()> { match find_extrinsic_by_name(&chain.pallets, "Sudo", "sudo").await { - Ok(_) => + Ok(_) => { if !self.sudo { self.sudo = cli .confirm( @@ -266,12 +270,14 @@ impl CallParachainCommand { ) .initial_value(false) .interact()?; - }, - Err(_) => + } + }, + Err(_) => { if self.sudo { cli.warning("NOTE: sudo extrinsic is not supported by the chain. Ignoring `--sudo` flag.")?; self.sudo = false; - }, + } + }, } Ok(()) } @@ -286,11 +292,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() || - self.extrinsic.is_none() || - self.args.is_empty() || - self.url.is_none() || - self.suri.is_none() + self.pallet.is_none() + || self.extrinsic.is_none() + || self.args.is_empty() + || self.url.is_none() + || self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -377,8 +383,9 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { From d1cbcf4bbe68c31232274ab6ba854e3a03bf21ab Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 9 Dec 2024 09:01:58 +0100 Subject: [PATCH 11/15] chore: fmt --- crates/pop-cli/src/commands/call/parachain.rs | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 8d5709e8..523a144d 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,9 +94,8 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call - || !cli - .confirm("Do you want to perform another call?") + if !prompt_to_repeat_call || + !cli.confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -159,9 +158,8 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => { - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? - }, + Some(ref extrinsic_name) => + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -202,9 +200,8 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => { - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? - }, + None => + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; return Ok(CallParachain { @@ -231,9 +228,8 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -262,7 +258,7 @@ impl CallParachainCommand { // execute the call via sudo. async fn configure_sudo(&mut self, chain: &Chain, cli: &mut impl Cli) -> Result<()> { match find_extrinsic_by_name(&chain.pallets, "Sudo", "sudo").await { - Ok(_) => { + Ok(_) => if !self.sudo { self.sudo = cli .confirm( @@ -270,14 +266,12 @@ impl CallParachainCommand { ) .initial_value(false) .interact()?; - } - }, - Err(_) => { + }, + Err(_) => if self.sudo { cli.warning("NOTE: sudo extrinsic is not supported by the chain. Ignoring `--sudo` flag.")?; self.sudo = false; - } - }, + }, } Ok(()) } @@ -292,11 +286,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() - || self.extrinsic.is_none() - || self.args.is_empty() - || self.url.is_none() - || self.suri.is_none() + self.pallet.is_none() || + self.extrinsic.is_none() || + self.args.is_empty() || + self.url.is_none() || + self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -383,9 +377,8 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { From fd8b74e61ddd2b66d788f03241ba372d841e91c6 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 9 Dec 2024 11:31:10 +0100 Subject: [PATCH 12/15] test: fix wrong assert --- crates/pop-cli/src/commands/call/parachain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 523a144d..99154b9c 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -708,7 +708,7 @@ mod tests { assert_eq!(call_parachain.extrinsic.name, "place_order_allow_death"); assert_eq!(call_parachain.args, ["10000".to_string(), "2000".to_string()].to_vec()); assert_eq!(call_parachain.suri, "//Bob"); - assert!(!call_config.sudo); + assert!(!call_parachain.sudo); assert_eq!(call_parachain.display(&chain), "pop call parachain --pallet OnDemand --extrinsic place_order_allow_death --args \"10000\" \"2000\" --url wss://polkadot-rpc.publicnode.com/ --suri //Bob"); cli.verify() } From 709ade9a610e5fd8636c37465b6e91835f69f188 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 9 Dec 2024 11:33:06 +0100 Subject: [PATCH 13/15] docs: improve comments and output messages --- crates/pop-cli/src/commands/call/parachain.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index 99154b9c..d14787fd 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -269,7 +269,9 @@ impl CallParachainCommand { }, Err(_) => if self.sudo { - cli.warning("NOTE: sudo extrinsic is not supported by the chain. Ignoring `--sudo` flag.")?; + cli.warning( + "NOTE: sudo is not supported by the chain. Ignoring `--sudo` flag.", + )?; self.sudo = false; }, } @@ -808,9 +810,9 @@ mod tests { call_data: Some("0x00000411".to_string()), sudo: true, }; - let mut cli = MockCli::new().expect_intro("Call a parachain").expect_warning( - "NOTE: sudo extrinsic is not supported by the chain. Ignoring `--sudo` flag.", - ); + let mut cli = MockCli::new() + .expect_intro("Call a parachain") + .expect_warning("NOTE: sudo is not supported by the chain. Ignoring `--sudo` flag."); let chain = call_config.configure_chain(&mut cli).await?; call_config.configure_sudo(&chain, &mut cli).await?; assert!(!call_config.sudo); From 2883e9088659d001363cca382fe0bb921a1150b5 Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 9 Dec 2024 12:18:09 +0100 Subject: [PATCH 14/15] refactor: split decode_call_data logic outside sign_and_submit_extrinsic_with_call_data --- crates/pop-cli/src/commands/call/parachain.rs | 45 +++++++++++-------- crates/pop-parachains/src/call/mod.rs | 10 +++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index d14787fd..fae486ae 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,8 +94,9 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call || - !cli.confirm("Do you want to perform another call?") + if !prompt_to_repeat_call + || !cli + .confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -158,8 +159,9 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, + Some(ref extrinsic_name) => { + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? + }, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -200,8 +202,9 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, + None => { + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? + }, }; return Ok(CallParachain { @@ -228,8 +231,9 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -258,7 +262,7 @@ impl CallParachainCommand { // execute the call via sudo. async fn configure_sudo(&mut self, chain: &Chain, cli: &mut impl Cli) -> Result<()> { match find_extrinsic_by_name(&chain.pallets, "Sudo", "sudo").await { - Ok(_) => + Ok(_) => { if !self.sudo { self.sudo = cli .confirm( @@ -266,14 +270,16 @@ impl CallParachainCommand { ) .initial_value(false) .interact()?; - }, - Err(_) => + } + }, + Err(_) => { if self.sudo { cli.warning( "NOTE: sudo is not supported by the chain. Ignoring `--sudo` flag.", )?; self.sudo = false; - }, + } + }, } Ok(()) } @@ -288,11 +294,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() || - self.extrinsic.is_none() || - self.args.is_empty() || - self.url.is_none() || - self.suri.is_none() + self.pallet.is_none() + || self.extrinsic.is_none() + || self.args.is_empty() + || self.url.is_none() + || self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -379,8 +385,9 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm && - !cli.confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm + && !cli + .confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { diff --git a/crates/pop-parachains/src/call/mod.rs b/crates/pop-parachains/src/call/mod.rs index a1828840..17d04a82 100644 --- a/crates/pop-parachains/src/call/mod.rs +++ b/crates/pop-parachains/src/call/mod.rs @@ -208,6 +208,16 @@ mod tests { Ok(()) } + #[tokio::test] + async fn decode_call_data_works() -> Result<()> { + assert!(matches!(decode_call_data("wrongcalldata"), Err(Error::CallDataDecodingError(..)))); + let client = set_up_client("wss://rpc1.paseo.popnetwork.xyz").await?; + let extrinsic = construct_extrinsic("System", "remark", vec!["0x11".to_string()]).await?; + let expected_call_data = extrinsic.encode_call_data(&client.metadata())?; + assert_eq!(decode_call_data("0x00000411")?, expected_call_data); + Ok(()) + } + #[tokio::test] async fn sign_and_submit_wrong_extrinsic_fails() -> Result<()> { let client = set_up_client(POP_NETWORK_TESTNET_URL).await?; From 34da761e446ca754c2678a9e44a64b69176b6d6c Mon Sep 17 00:00:00 2001 From: AlexD10S Date: Mon, 9 Dec 2024 17:22:51 +0100 Subject: [PATCH 15/15] fix: test construct_sudo_extrinsic_works and formatting --- crates/pop-cli/src/commands/call/parachain.rs | 45 ++++++++----------- crates/pop-parachains/src/call/mod.rs | 15 ++----- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/crates/pop-cli/src/commands/call/parachain.rs b/crates/pop-cli/src/commands/call/parachain.rs index fae486ae..d14787fd 100644 --- a/crates/pop-cli/src/commands/call/parachain.rs +++ b/crates/pop-cli/src/commands/call/parachain.rs @@ -94,9 +94,8 @@ impl CallParachainCommand { break; } - if !prompt_to_repeat_call - || !cli - .confirm("Do you want to perform another call?") + if !prompt_to_repeat_call || + !cli.confirm("Do you want to perform another call?") .initial_value(false) .interact()? { @@ -159,9 +158,8 @@ impl CallParachainCommand { // Resolve extrinsic. let extrinsic = match self.extrinsic { - Some(ref extrinsic_name) => { - find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await? - }, + Some(ref extrinsic_name) => + find_extrinsic_by_name(&chain.pallets, &pallet.name, extrinsic_name).await?, None => { let mut prompt_extrinsic = cli.select("Select the extrinsic to call:"); for extrinsic in &pallet.extrinsics { @@ -202,9 +200,8 @@ impl CallParachainCommand { // Resolve who is signing the extrinsic. let suri = match self.suri.as_ref() { Some(suri) => suri.clone(), - None => { - cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()? - }, + None => + cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; return Ok(CallParachain { @@ -231,9 +228,8 @@ impl CallParachainCommand { None => &cli.input("Signer of the extrinsic:").default_input(DEFAULT_URI).interact()?, }; cli.info(format!("Encoded call data: {}", call_data))?; - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { @@ -262,7 +258,7 @@ impl CallParachainCommand { // execute the call via sudo. async fn configure_sudo(&mut self, chain: &Chain, cli: &mut impl Cli) -> Result<()> { match find_extrinsic_by_name(&chain.pallets, "Sudo", "sudo").await { - Ok(_) => { + Ok(_) => if !self.sudo { self.sudo = cli .confirm( @@ -270,16 +266,14 @@ impl CallParachainCommand { ) .initial_value(false) .interact()?; - } - }, - Err(_) => { + }, + Err(_) => if self.sudo { cli.warning( "NOTE: sudo is not supported by the chain. Ignoring `--sudo` flag.", )?; self.sudo = false; - } - }, + }, } Ok(()) } @@ -294,11 +288,11 @@ impl CallParachainCommand { // Function to check if all required fields are specified. fn requires_user_input(&self) -> bool { - self.pallet.is_none() - || self.extrinsic.is_none() - || self.args.is_empty() - || self.url.is_none() - || self.suri.is_none() + self.pallet.is_none() || + self.extrinsic.is_none() || + self.args.is_empty() || + self.url.is_none() || + self.suri.is_none() } /// Replaces file arguments with their contents, leaving other arguments unchanged. @@ -385,9 +379,8 @@ impl CallParachain { tx: DynamicPayload, cli: &mut impl Cli, ) -> Result<()> { - if !self.skip_confirm - && !cli - .confirm("Do you want to submit the extrinsic?") + if !self.skip_confirm && + !cli.confirm("Do you want to submit the extrinsic?") .initial_value(true) .interact()? { diff --git a/crates/pop-parachains/src/call/mod.rs b/crates/pop-parachains/src/call/mod.rs index 17d04a82..967e8b74 100644 --- a/crates/pop-parachains/src/call/mod.rs +++ b/crates/pop-parachains/src/call/mod.rs @@ -208,16 +208,6 @@ mod tests { Ok(()) } - #[tokio::test] - async fn decode_call_data_works() -> Result<()> { - assert!(matches!(decode_call_data("wrongcalldata"), Err(Error::CallDataDecodingError(..)))); - let client = set_up_client("wss://rpc1.paseo.popnetwork.xyz").await?; - let extrinsic = construct_extrinsic("System", "remark", vec!["0x11".to_string()]).await?; - let expected_call_data = extrinsic.encode_call_data(&client.metadata())?; - assert_eq!(decode_call_data("0x00000411")?, expected_call_data); - Ok(()) - } - #[tokio::test] async fn sign_and_submit_wrong_extrinsic_fails() -> Result<()> { let client = set_up_client(POP_NETWORK_TESTNET_URL).await?; @@ -237,9 +227,12 @@ mod tests { #[tokio::test] async fn construct_sudo_extrinsic_works() -> Result<()> { + let client = set_up_client("wss://rpc1.paseo.popnetwork.xyz").await?; + let pallets = parse_chain_metadata(&client).await?; + let force_transfer = find_extrinsic_by_name(&pallets, "Balances", "force_transfer").await?; let extrinsic = construct_extrinsic( "Balances", - "force_transfer", + &force_transfer, vec![ "Id(5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty)".to_string(), "Id(5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy)".to_string(),