diff --git a/rusk-wallet/src/bin/command.rs b/rusk-wallet/src/bin/command.rs index 9919612dd..65c6214c3 100644 --- a/rusk-wallet/src/bin/command.rs +++ b/rusk-wallet/src/bin/command.rs @@ -27,7 +27,7 @@ use rusk_wallet::{ }; use wallet_core::BalanceInfo; -use crate::io::prompt; +use crate::io::prompt::{self, request_contract_call_method}; use crate::settings::Settings; use crate::{WalletFile, WalletPath}; @@ -569,35 +569,51 @@ impl Command { .try_into() .map_err(|_| Error::InvalidContractId)?; - let call = ContractCall::new(contract_id, fn_name, &fn_args) - .map_err(|_| Error::Rkyv)?; + match request_contract_call_method()? { + prompt::ContractCall::Query => { + let contract_id = hex::encode(contract_id); - let tx = match address { - Address::Shielded(_) => { - wallet.sync().await?; - wallet - .phoenix_execute( - addr_idx, - Dusk::from(0), - gas, - call.into(), - ) - .await + let http_call = wallet + .http_contract_call(contract_id, &fn_name, fn_args) + .await?; + + Ok(RunResult::ContractCallQuery(http_call)) } - Address::Public(_) => { - wallet - .moonlight_execute( - addr_idx, - Dusk::from(0), - Dusk::from(0), - gas, - call.into(), - ) - .await + prompt::ContractCall::Transaction => { + let call = ContractCall::new( + contract_id, + fn_name.clone(), + &fn_args, + ) + .map_err(|_| Error::Rkyv)?; + + let tx = match address { + Address::Shielded(_) => { + wallet.sync().await?; + wallet + .phoenix_execute( + addr_idx, + Dusk::from(0), + gas, + call.into(), + ) + .await + } + Address::Public(_) => { + wallet + .moonlight_execute( + addr_idx, + Dusk::from(0), + Dusk::from(0), + gas, + call.into(), + ) + .await + } + }?; + Ok(RunResult::ContractCallTx(tx.hash())) } - }?; - - Ok(RunResult::Tx(tx.hash())) + } } Self::ContractDeploy { @@ -688,6 +704,8 @@ pub enum RunResult<'a> { Profile((u8, &'a Profile)), Profiles(&'a Vec), ContractId([u8; CONTRACT_ID_BYTES]), + ContractCallTx(BlsScalar), + ContractCallQuery(Vec), ExportedKeys(PathBuf, PathBuf), Create(), Restore(), @@ -765,6 +783,13 @@ impl fmt::Display for RunResult<'_> { ContractId(bytes) => { write!(f, "> Contract ID: {}", hex::encode(bytes)) } + ContractCallTx(scalar) => { + let hash = hex::encode(scalar.to_bytes()); + writeln!(f, "> Contract call transaction hash: {hash}",) + } + ContractCallQuery(bytes) => { + writeln!(f, "> Http contract query: {:?}", bytes) + } ExportedKeys(pk, kp) => { let pk = pk.display(); let kp = kp.display(); diff --git a/rusk-wallet/src/bin/interactive.rs b/rusk-wallet/src/bin/interactive.rs index 969a0cd3a..0da034629 100644 --- a/rusk-wallet/src/bin/interactive.rs +++ b/rusk-wallet/src/bin/interactive.rs @@ -92,22 +92,26 @@ pub(crate) async fn run_loop( prompt::show_cursor()?; // output results println!("\r{}", res); - if let RunResult::Tx(hash) = res { - let tx_id = hex::encode(hash.to_bytes()); - - // Wait for transaction confirmation - // from network - let gql = GraphQL::new( - settings.state.to_string(), - io::status::interactive, - )?; - gql.wait_for(&tx_id).await?; - - if let Some(explorer) = &settings.explorer { - let url = format!("{explorer}{tx_id}"); - println!("> URL: {url}"); - prompt::launch_explorer(url)?; + match res { + RunResult::Tx(hash) + | RunResult::ContractCallTx(hash) => { + let tx_id = hex::encode(hash.to_bytes()); + + // Wait for transaction confirmation + // from network + let gql = GraphQL::new( + settings.state.to_string(), + io::status::interactive, + )?; + gql.wait_for(&tx_id).await?; + + if let Some(explorer) = &settings.explorer { + let url = format!("{explorer}{tx_id}"); + println!("> URL: {url}"); + prompt::launch_explorer(url)?; + } } + _ => (), } } } diff --git a/rusk-wallet/src/bin/io/prompt.rs b/rusk-wallet/src/bin/io/prompt.rs index 7d941b5f4..ff6adf204 100644 --- a/rusk-wallet/src/bin/io/prompt.rs +++ b/rusk-wallet/src/bin/io/prompt.rs @@ -371,7 +371,8 @@ pub(crate) fn request_address( pub(crate) fn request_contract_code() -> anyhow::Result { let validator = |path_str: &str| { let path = PathBuf::from(path_str); - if path.extension().map_or(false, |ext| ext == "wasm") { + if path.extension().map_or(false, |ext| ext == "wasm") && path.exists() + { Ok(Validation::Valid) } else { Ok(Validation::Invalid("Not a valid directory".into())) diff --git a/rusk-wallet/src/bin/main.rs b/rusk-wallet/src/bin/main.rs index 1e9c4b9ee..0dc8e69dd 100644 --- a/rusk-wallet/src/bin/main.rs +++ b/rusk-wallet/src/bin/main.rs @@ -401,6 +401,20 @@ async fn exec() -> anyhow::Result<()> { RunResult::ContractId(id) => { println!("Contract ID: {:?}", id); } + RunResult::ContractCallTx(scalar) => { + let tx_id = hex::encode(scalar.to_bytes()); + + // Wait for transaction confirmation from network + let gql = GraphQL::new(settings.state, status::headless)?; + gql.wait_for(&tx_id).await?; + + println!("{tx_id}"); + + + } + RunResult::ContractCallQuery(bytes) => { + println!("HTTP call result: {:?}", bytes); + } RunResult::Settings() => {} RunResult::Create() | RunResult::Restore() => {} } diff --git a/rusk-wallet/src/clients/sync.rs b/rusk-wallet/src/clients/sync.rs index bf03621b5..9d515f1c3 100644 --- a/rusk-wallet/src/clients/sync.rs +++ b/rusk-wallet/src/clients/sync.rs @@ -46,7 +46,7 @@ pub(crate) async fn sync_db( let mut stream = client .call_raw( CONTRACTS_TARGET, - TRANSFER_CONTRACT, + Some(TRANSFER_CONTRACT.to_string()), "leaves_from_pos", &req, true, diff --git a/rusk-wallet/src/gql.rs b/rusk-wallet/src/gql.rs index c361db99f..0d35c1b31 100644 --- a/rusk-wallet/src/gql.rs +++ b/rusk-wallet/src/gql.rs @@ -175,7 +175,7 @@ impl GraphQL { /// Call the graphql endpoint of a node pub async fn query(&self, query: &str) -> Result, Error> { self.client - .call("graphql", None, "query", query.as_bytes()) + .call("graphql", None::, "query", query.as_bytes()) .await } } diff --git a/rusk-wallet/src/rues.rs b/rusk-wallet/src/rues.rs index 8c8008b5c..9eed71e4c 100644 --- a/rusk-wallet/src/rues.rs +++ b/rusk-wallet/src/rues.rs @@ -54,8 +54,11 @@ impl RuesHttpClient { { let data = rkyv::to_bytes(value).map_err(|_| Error::Rkyv)?.to_vec(); + let contract: Option<&str> = contract.into(); + let contract: Option = contract.map(|e| e.to_owned()); + let response = self - .call_raw(CONTRACTS_TARGET, contract.into(), method, &data, false) + .call_raw(CONTRACTS_TARGET, contract, method, &data, false) .await?; Ok(response.bytes().await?.to_vec()) @@ -79,7 +82,7 @@ impl RuesHttpClient { request: &[u8], ) -> Result, Error> where - E: Into>, + E: Into>, { let response = self.call_raw(target, entity, topic, request, false).await?; @@ -97,7 +100,7 @@ impl RuesHttpClient { feed: bool, ) -> Result where - E: Into>, + E: Into>, { let uri = &self.uri; let entity = entity.into().map(|e| format!(":{e}")).unwrap_or_default(); diff --git a/rusk-wallet/src/wallet.rs b/rusk-wallet/src/wallet.rs index 52d6e5220..6f992bc69 100644 --- a/rusk-wallet/src/wallet.rs +++ b/rusk-wallet/src/wallet.rs @@ -623,6 +623,23 @@ impl Wallet { Ok(gas_prices) } + + /// do a contract call over http + pub async fn http_contract_call( + &self, + contract_id: String, + fn_name: &str, + fn_args: Vec, + ) -> Result, Error> { + let client = self.state()?.client(); + + // query the rusk vm + let response = client + .call("contracts", Some(contract_id), fn_name, &fn_args) + .await?; + + Ok(response) + } } /// This structs represent a Note decoded enriched with useful chain information