Skip to content

Commit

Permalink
pop call contract implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
ndkazu committed Dec 21, 2024
1 parent 2f7b5a8 commit a449edf
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 21 deletions.
73 changes: 63 additions & 10 deletions crates/pop-cli/src/commands/call/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use pop_contracts::{
parse_account, set_up_call, CallExec, CallOpts, DefaultEnvironment, Verbosity,
};
use sp_weights::Weight;
use std::path::{Path, PathBuf};
use std::path::PathBuf;

const DEFAULT_URL: &str = "ws://localhost:9944/";
const DEFAULT_URI: &str = "//Alice";
Expand All @@ -28,6 +28,9 @@ pub struct CallContractCommand {
/// Path to the contract build directory or a contract artifact.
#[arg(short, long)]
path: Option<PathBuf>,
/// Directory path without flag for your project [default: current directory]
#[arg(value_name = "PATH", index = 1, conflicts_with = "path")]
pub(crate) path_pos: Option<PathBuf>,
/// The address of the contract to call.
#[arg(short, long, env = "CONTRACT")]
contract: Option<String>,
Expand Down Expand Up @@ -109,7 +112,14 @@ impl CallContractCommand {

fn display(&self) -> String {
let mut full_message = "pop call contract".to_string();
if let Some(path) = &self.path {
let path_flag = self.path.clone();
let project_path = if let Some(ref path_pos) = self.path_pos {
Some(path_pos) // Use positional path if present
} else {
path_flag.as_ref() // Otherwise, use the named path
};

if let Some(path) = &project_path {
full_message.push_str(&format!(" --path {}", path.display()));
}
if let Some(contract) = &self.contract {
Expand Down Expand Up @@ -148,11 +158,21 @@ impl CallContractCommand {

/// If the contract has not been built, build it in release mode.
async fn ensure_contract_built(&self, cli: &mut impl Cli) -> Result<()> {
let path_flag = self.path.clone();
let project_path = if let Some(ref path_pos) = self.path_pos {
Some(path_pos) // Use positional path if present
} else {
path_flag.as_ref() // Otherwise, use the named path
};
// Build the contract in release mode
cli.warning("NOTE: contract has not yet been built.")?;
let spinner = spinner();
spinner.start("Building contract in RELEASE mode...");
let result = match build_smart_contract(self.path.as_deref(), true, Verbosity::Quiet) {
let result = match build_smart_contract(
project_path.as_deref().map(|v| &**v),
true,
Verbosity::Quiet,
) {
Ok(result) => result,
Err(e) => {
return Err(anyhow!(format!(
Expand Down Expand Up @@ -182,14 +202,28 @@ impl CallContractCommand {

/// Checks whether building the contract is required
fn is_contract_build_required(&self) -> bool {
self.path
let path_flag = self.path.clone();
let project_path = if let Some(ref path_pos) = self.path_pos {
Some(path_pos) // Use positional path if present
} else {
path_flag.as_ref() // Otherwise, use the named path
};

project_path
.as_ref()
.map(|p| p.is_dir() && !has_contract_been_built(Some(p)))
.unwrap_or_default()
}

/// Configure the call based on command line arguments/call UI.
async fn configure(&mut self, cli: &mut impl Cli, repeat: bool) -> Result<()> {
let path_flag = self.path.clone();
let mut project_path: Option<PathBuf> = if let Some(ref path_pos) = self.path_pos {
Some(path_pos.to_path_buf()) // Use positional path if present
} else {
path_flag // Otherwise, use the named path
};

// Show intro on first run.
if !repeat {
cli.intro("Call a contract")?;
Expand All @@ -201,16 +235,15 @@ impl CallContractCommand {
}

// Resolve path.
if self.path.is_none() {
if project_path.is_none() {
let input_path: String = cli
.input("Where is your project or contract artifact located?")
.placeholder("./")
.default_input("./")
.interact()?;
self.path = Some(PathBuf::from(input_path));
project_path = Some(PathBuf::from(input_path));
}
let contract_path = self
.path
let contract_path = project_path
.as_ref()
.expect("path is guaranteed to be set as input as prompted when None; qed");

Expand Down Expand Up @@ -357,15 +390,23 @@ impl CallContractCommand {
cli: &mut impl Cli,
prompt_to_repeat_call: bool,
) -> Result<()> {
let path_flag = self.path.clone();
let project_path = if let Some(ref path_pos) = self.path_pos {
Some(path_pos) // Use positional path if present
} else {
path_flag.as_ref() // Otherwise, use the named path
};

let message = match &self.message {
Some(message) => message.to_string(),
None => {
return Err(anyhow!("Please specify the message to call."));
},
};
// Disable wallet signing and display warning if the call is read-only.
let path = PathBuf::from("./");
let message_metadata =
get_message(self.path.as_deref().unwrap_or_else(|| Path::new("./")), &message)?;
get_message(project_path.as_deref().unwrap_or_else(|| &path), &message)?;
if !message_metadata.mutates && self.use_wallet {
cli.warning("NOTE: Signing is not required for this read-only call. The '--use-wallet' flag will be ignored.")?;
self.use_wallet = false;
Expand All @@ -378,7 +419,7 @@ impl CallContractCommand {
},
};
let call_exec = match set_up_call(CallOpts {
path: self.path.clone(),
path: project_path.cloned(),
contract,
message,
args: self.args.clone(),
Expand Down Expand Up @@ -564,6 +605,7 @@ mod tests {
// Contract deployed on Pop Network testnet, test get
CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: Some("get".to_string()),
args: vec![].to_vec(),
Expand Down Expand Up @@ -600,6 +642,7 @@ mod tests {

let mut call_config = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: Some("flip".to_string()),
args: vec![].to_vec(),
Expand Down Expand Up @@ -637,6 +680,7 @@ mod tests {
// From .contract file
let mut call_config = CallContractCommand {
path: Some(current_dir.join("pop-contracts/tests/files/testing.contract")),
path_pos: Some(current_dir.join("pop-contracts/tests/files/testing.contract")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: Some("flip".to_string()),
args: vec![].to_vec(),
Expand Down Expand Up @@ -723,6 +767,7 @@ mod tests {
// Contract deployed on Pop Network testnet, test get
let mut call_config = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: Some("get".to_string()),
args: vec![].to_vec(),
Expand Down Expand Up @@ -789,6 +834,7 @@ mod tests {

let mut call_config = CallContractCommand {
path: None,
path_pos: None,
contract: None,
message: None,
args: vec![].to_vec(),
Expand Down Expand Up @@ -876,6 +922,7 @@ mod tests {

let mut call_config = CallContractCommand {
path: None,
path_pos: None,
contract: None,
message: None,
args: vec![].to_vec(),
Expand Down Expand Up @@ -964,6 +1011,7 @@ mod tests {

let mut call_config = CallContractCommand {
path: None,
path_pos: None,
contract: None,
message: None,
args: vec![].to_vec(),
Expand Down Expand Up @@ -1023,6 +1071,7 @@ mod tests {
// Test the path is a folder with an invalid build.
let mut command = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: None,
message: None,
args: vec![].to_vec(),
Expand Down Expand Up @@ -1073,6 +1122,7 @@ mod tests {
assert!(matches!(
CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: None,
args: vec![].to_vec(),
Expand All @@ -1092,6 +1142,7 @@ mod tests {
assert!(matches!(
CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: None,
message: Some("get".to_string()),
args: vec![].to_vec(),
Expand All @@ -1116,6 +1167,7 @@ mod tests {
let temp_dir = new_environment("testing")?;
let call_config = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: None,
args: vec![].to_vec(),
Expand Down Expand Up @@ -1147,6 +1199,7 @@ mod tests {
let temp_dir = new_environment("testing")?;
let call_config = CallContractCommand {
path: Some(temp_dir.path().join("testing")),
path_pos: Some(temp_dir.path().join("testing")),
contract: Some("15XausWjFLBBFLDXUSBRfSfZk25warm4wZRV4ZxhZbfvjrJm".to_string()),
message: None,
args: vec![].to_vec(),
Expand Down
6 changes: 5 additions & 1 deletion crates/pop-cli/src/commands/up/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ impl UpContractCommand {
Cli.warning("NOTE: contract has not yet been built.")?;
let spinner = spinner();
spinner.start("Building contract in RELEASE mode...");
let result = match build_smart_contract(project_path.as_deref().map(|v| &**v), true, Verbosity::Quiet) {
let result = match build_smart_contract(
project_path.as_deref().map(|v| &**v),
true,
Verbosity::Quiet,
) {
Ok(result) => result,
Err(e) => {
Cli.outro_cancel(format!("🚫 An error occurred building your contract: {e}\nUse `pop build` to retry with build output."))?;
Expand Down
28 changes: 18 additions & 10 deletions crates/pop-cli/tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,22 +67,22 @@ async fn contract_lifecycle() -> Result<()> {
.success();
assert!(temp_dir.join("test_contract").exists());

/* // pop build --path ./test_contract --release
Command::cargo_bin("pop")
.unwrap()
.current_dir(&temp_dir)
.args(&["build", "--path", "./test_contract", "--release"])
.assert()
.success();
*/
/* // pop build --path ./test_contract --release
Command::cargo_bin("pop")
.unwrap()
.current_dir(&temp_dir)
.args(&["build", "--path", "./test_contract", "--release"])
.assert()
.success();
*/
// pop build ./test_contract --release
Command::cargo_bin("pop")
.unwrap()
.current_dir(&temp_dir)
.args(&["build", "./test_contract", "--release"])
.assert()
.success();

println!("Contract built!!");

// Verify that the directory target has been created
Expand All @@ -103,7 +103,15 @@ async fn contract_lifecycle() -> Result<()> {
Command::cargo_bin("pop")
.unwrap()
.current_dir(&temp_dir.join("test_contract"))
.args(&["up", "contract", "--path", "./test_contract","--upload-only", "--url", default_endpoint])
.args(&[
"up",
"contract",
"--path",
"./test_contract",
"--upload-only",
"--url",
default_endpoint,
])
.assert()
.success();
/*// pop up contract --upload-only
Expand Down

0 comments on commit a449edf

Please sign in to comment.