Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: parse user inputs for Option arguments #332

Merged
merged 13 commits into from
Nov 22, 2024
30 changes: 18 additions & 12 deletions crates/pop-cli/src/commands/call/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub struct CallContractCommand {
#[clap(long, short)]
message: Option<String>,
/// The constructor arguments, encoded as strings.
#[clap(long, num_args = 0..)]
#[clap(long, num_args = 0..,)]
args: Vec<String>,
/// The value to be transferred as part of the call.
#[clap(name = "value", short = 'v', long, default_value = DEFAULT_PAYABLE_VALUE)]
Expand Down Expand Up @@ -96,7 +96,7 @@ impl CallContractCommand {
full_message.push_str(&format!(" --message {}", message));
}
if !self.args.is_empty() {
full_message.push_str(&format!(" --args {}", self.args.join(" ")));
full_message.push_str(&format!(" --args {}", self.args.join(",")));
}
if self.value != DEFAULT_PAYABLE_VALUE {
full_message.push_str(&format!(" --value {}", self.value));
Expand Down Expand Up @@ -230,11 +230,15 @@ impl CallContractCommand {
// Resolve message arguments.
let mut contract_args = Vec::new();
for arg in &message.args {
contract_args.push(
cli.input(format!("Enter the value for the parameter: {}", arg.label))
.placeholder(&format!("Type required: {}", &arg.type_name))
.interact()?,
);
let mut input = cli
.input(format!("Enter the value for the parameter: {}", arg.label))
.placeholder(&format!("Type required: {}", arg.type_name));

// Set default input only if the parameter type is `Option` (Not mandatory)
if arg.type_name == "Option" {
input = input.default_input("");
}
contract_args.push(input.interact()?);
}
self.args = contract_args;

Expand Down Expand Up @@ -478,7 +482,7 @@ mod tests {
.expect_warning("Your call has not been executed.")
.expect_info("Gas limit: Weight { ref_time: 100, proof_size: 10 }");

let mut call_config = CallContractCommand {
let call_config = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: Some("flip".to_string()),
Expand Down Expand Up @@ -545,7 +549,7 @@ mod tests {
.expect_outro("Contract calling complete.");

// Contract deployed on Pop Network testnet, test get
let mut call_config = CallContractCommand {
let call_config = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: Some("get".to_string()),
Expand Down Expand Up @@ -671,6 +675,7 @@ mod tests {
.expect_input("Enter the proof size limit:", "".into()) // Only if call
.expect_input("Enter the gas limit:", "".into()) // Only if call
.expect_input("Value to transfer to the call:", "50".into()) // Only if payable
.expect_input("Enter the value for the parameter: number", "2".into()) // Args for specific_flip
.expect_input("Enter the value for the parameter: new_value", "true".into()) // Args for specific_flip
.expect_select::<PathBuf>(
"Select the message to call:",
Expand All @@ -691,7 +696,7 @@ mod tests {
"Where is your project located?",
temp_dir.path().join("testing").display().to_string(),
).expect_info(format!(
"pop call contract --path {} --contract 15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm --message specific_flip --args true --value 50 --url wss://rpc1.paseo.popnetwork.xyz/ --suri //Alice --execute",
"pop call contract --path {} --contract 15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm --message specific_flip --args true,2 --value 50 --url wss://rpc1.paseo.popnetwork.xyz/ --suri //Alice --execute",
temp_dir.path().join("testing").display().to_string(),
));

Expand All @@ -715,8 +720,9 @@ mod tests {
Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string())
);
assert_eq!(call_config.message, Some("specific_flip".to_string()));
assert_eq!(call_config.args.len(), 1);
assert_eq!(call_config.args.len(), 2);
assert_eq!(call_config.args[0], "true".to_string());
assert_eq!(call_config.args[1], "2".to_string());
assert_eq!(call_config.value, "50".to_string());
assert_eq!(call_config.gas_limit, None);
assert_eq!(call_config.proof_size, None);
Expand All @@ -725,7 +731,7 @@ mod tests {
assert!(call_config.execute);
assert!(!call_config.dry_run);
assert_eq!(call_config.display(), format!(
"pop call contract --path {} --contract 15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm --message specific_flip --args true --value 50 --url wss://rpc1.paseo.popnetwork.xyz/ --suri //Alice --execute",
"pop call contract --path {} --contract 15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm --message specific_flip --args true,2 --value 50 --url wss://rpc1.paseo.popnetwork.xyz/ --suri //Alice --execute",
temp_dir.path().join("testing").display().to_string(),
));

Expand Down
4 changes: 2 additions & 2 deletions crates/pop-cli/src/commands/up/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub struct UpContractCommand {
#[clap(name = "constructor", long, default_value = "new")]
constructor: String,
/// The constructor arguments, encoded as strings.
#[clap(long, num_args = 0..)]
#[clap(long, num_args = 0..,)]
args: Vec<String>,
/// Transfers an initial balance to the instantiated contract.
#[clap(name = "value", long, default_value = "0")]
Expand Down Expand Up @@ -321,7 +321,7 @@ mod tests {
let command = UpContractCommand {
path: None,
constructor: "new".to_string(),
args: vec!["false".to_string()].to_vec(),
args: vec![],
value: "0".to_string(),
gas_limit: None,
proof_size: None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
errors::Error,
utils::{
helpers::{get_manifest_path, parse_account, parse_balance},
metadata::{process_function_args, FunctionType},
signer::create_signer,
},
};
Expand All @@ -20,8 +21,6 @@ use subxt::{Config, PolkadotConfig as DefaultConfig};
use subxt_signer::sr25519::Keypair;
use url::Url;

pub mod metadata;

/// Attributes for the `call` command.
pub struct CallOpts {
/// Path to the contract build directory.
Expand Down Expand Up @@ -53,7 +52,7 @@ pub struct CallOpts {
/// * `call_opts` - options for the `call` command.
pub async fn set_up_call(
call_opts: CallOpts,
) -> anyhow::Result<CallExec<DefaultConfig, DefaultEnvironment, Keypair>> {
) -> Result<CallExec<DefaultConfig, DefaultEnvironment, Keypair>, Error> {
let token_metadata = TokenMetadata::query::<DefaultConfig>(&call_opts.url).await?;
let manifest_path = get_manifest_path(call_opts.path.as_deref())?;
let signer = create_signer(&call_opts.suri)?;
Expand All @@ -67,10 +66,17 @@ pub async fn set_up_call(
parse_balance(&call_opts.value)?;

let contract: <DefaultConfig as Config>::AccountId = parse_account(&call_opts.contract)?;
// Process the argument values input by the user.
let args = process_function_args(
call_opts.path.unwrap_or_else(|| PathBuf::from("./")),
&call_opts.message,
call_opts.args,
FunctionType::Message,
)?;

let call_exec: CallExec<DefaultConfig, DefaultEnvironment, Keypair> =
CallCommandBuilder::new(contract.clone(), &call_opts.message, extrinsic_opts)
.args(call_opts.args.clone())
.args(args)
.value(value.denominate_balance(&token_metadata)?)
.gas_limit(call_opts.gas_limit)
.proof_size(call_opts.proof_size)
Expand Down Expand Up @@ -212,11 +218,9 @@ mod tests {
suri: "//Alice".to_string(),
execute: false,
};
let call = set_up_call(call_opts).await;
assert!(call.is_err());
let error = call.err().unwrap();
assert_eq!(error.root_cause().to_string(), "Failed to find any contract artifacts in target directory. \nRun `cargo contract build --release` to generate the artifacts.");

assert!(
matches!(set_up_call(call_opts).await, Err(Error::AnyhowError(message)) if message.root_cause().to_string() == "Failed to find any contract artifacts in target directory. \nRun `cargo contract build --release` to generate the artifacts.")
);
Ok(())
}
#[tokio::test]
Expand All @@ -233,11 +237,9 @@ mod tests {
suri: "//Alice".to_string(),
execute: false,
};
let call = set_up_call(call_opts).await;
assert!(call.is_err());
let error = call.err().unwrap();
assert_eq!(error.root_cause().to_string(), "No 'ink' dependency found");

assert!(
matches!(set_up_call(call_opts).await, Err(Error::AnyhowError(message)) if message.root_cause().to_string() == "No 'ink' dependency found")
);
Ok(())
}

Expand Down
102 changes: 0 additions & 102 deletions crates/pop-contracts/src/call/metadata.rs

This file was deleted.

12 changes: 10 additions & 2 deletions crates/pop-contracts/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ pub enum Error {
InstallContractsNode(String),
#[error("{0}")]
InstantiateContractError(String),
#[error("Invalid constructor name: {0}")]
InvalidConstructorName(String),
#[error("Invalid message name: {0}")]
InvalidMessageName(String),
#[error("Invalid name: {0}")]
InvalidName(String),
#[error("IO error: {0}")]
Expand All @@ -36,6 +40,8 @@ pub enum Error {
KeyPairCreation(String),
#[error("Failed to get manifest path: {0}")]
ManifestPath(String),
#[error("Argument {0} is required")]
MissingArgument(String),
#[error("Failed to create new contract project: {0}")]
NewContract(String),
#[error("ParseError error: {0}")]
Expand All @@ -44,12 +50,14 @@ pub enum Error {
ParseSecretURI(String),
#[error("The `Repository` property is missing from the template variant")]
RepositoryMissing,
#[error("Sourcing error {0}")]
SourcingError(SourcingError),
#[error("Failed to execute test command: {0}")]
TestCommand(String),
#[error("Unsupported platform: {os}")]
UnsupportedPlatform { os: &'static str },
#[error("{0}")]
UploadContractError(String),
#[error("Sourcing error {0}")]
SourcingError(SourcingError),
#[error("Incorrect number of arguments provided. Expecting {expected}, {provided} provided")]
IncorrectArguments { expected: usize, provided: usize },
}
10 changes: 6 additions & 4 deletions crates/pop-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ mod utils;

pub use build::{build_smart_contract, is_supported, Verbosity};
pub use call::{
call_smart_contract, dry_run_call, dry_run_gas_estimate_call,
metadata::{get_messages, Message},
set_up_call, CallOpts,
call_smart_contract, dry_run_call, dry_run_gas_estimate_call, set_up_call, CallOpts,
};
pub use new::{create_smart_contract, is_valid_contract_name};
pub use node::{contracts_node_generator, is_chain_alive, run_contracts_node};
Expand All @@ -27,4 +25,8 @@ pub use up::{
dry_run_gas_estimate_instantiate, dry_run_upload, instantiate_smart_contract,
set_up_deployment, set_up_upload, upload_smart_contract, UpOpts,
};
pub use utils::{helpers::parse_account, signer::parse_hex_bytes};
pub use utils::{
helpers::parse_account,
metadata::{get_messages, ContractFunction},
signer::parse_hex_bytes,
};
10 changes: 9 additions & 1 deletion crates/pop-contracts/src/up.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::{
errors::Error,
utils::{
helpers::{get_manifest_path, parse_balance},
metadata::{process_function_args, FunctionType},
signer::create_signer,
},
};
Expand Down Expand Up @@ -62,10 +63,17 @@ pub async fn set_up_deployment(
let value: BalanceVariant<<DefaultEnvironment as Environment>::Balance> =
parse_balance(&up_opts.value)?;

// Process the argument values input by the user.
let args = process_function_args(
up_opts.path.unwrap_or_else(|| PathBuf::from("./")),
&up_opts.constructor,
up_opts.args,
FunctionType::Constructor,
)?;
let instantiate_exec: InstantiateExec<DefaultConfig, DefaultEnvironment, Keypair> =
InstantiateCommandBuilder::new(extrinsic_opts)
.constructor(up_opts.constructor.clone())
.args(up_opts.args.clone())
.args(args)
.value(value.denominate_balance(&token_metadata)?)
.gas_limit(up_opts.gas_limit)
.proof_size(up_opts.proof_size)
Expand Down
Loading