From 5c7f56e9755336ad42e70e294ad59cee0afa4bbe Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 11 Jul 2023 23:10:33 +0200 Subject: [PATCH 001/135] Added better gas estimation for low gas txs --- cw-orch/src/daemon/tx_builder.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cw-orch/src/daemon/tx_builder.rs b/cw-orch/src/daemon/tx_builder.rs index 3f15161dc..369dbb841 100644 --- a/cw-orch/src/daemon/tx_builder.rs +++ b/cw-orch/src/daemon/tx_builder.rs @@ -10,6 +10,8 @@ use secp256k1::All; use super::{sender::Sender, DaemonError}; const GAS_BUFFER: f64 = 1.2; +const BUFFER_CHANGE_LIMIT: u64 = 100_000; +const SMALL_GAS_BUFFER: f64 = 1.4; /// Struct used to build a raw transaction and broadcast it with a sender. #[derive(Clone, Debug)] @@ -98,7 +100,11 @@ impl TxBuilder { .await?; log::debug!("Simulated gas needed {:?}", sim_gas_used); - let gas_expected = sim_gas_used as f64 * GAS_BUFFER; + let gas_expected = if sim_gas_used < BUFFER_CHANGE_LIMIT{ + sim_gas_used as f64 * SMALL_GAS_BUFFER + }else{ + sim_gas_used as f64 * GAS_BUFFER + }; let fee_amount = gas_expected * (wallet.daemon_state.chain_data.fees.fee_tokens[0].fixed_min_gas_price + 0.00001); From ad236821c5a51ecb2a7180a8dfdef2f82b702fb1 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Tue, 11 Jul 2023 23:10:54 +0200 Subject: [PATCH 002/135] formatting --- cw-orch/src/daemon/tx_builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cw-orch/src/daemon/tx_builder.rs b/cw-orch/src/daemon/tx_builder.rs index 369dbb841..728a7c63b 100644 --- a/cw-orch/src/daemon/tx_builder.rs +++ b/cw-orch/src/daemon/tx_builder.rs @@ -100,9 +100,9 @@ impl TxBuilder { .await?; log::debug!("Simulated gas needed {:?}", sim_gas_used); - let gas_expected = if sim_gas_used < BUFFER_CHANGE_LIMIT{ + let gas_expected = if sim_gas_used < BUFFER_CHANGE_LIMIT { sim_gas_used as f64 * SMALL_GAS_BUFFER - }else{ + } else { sim_gas_used as f64 * GAS_BUFFER }; let fee_amount = gas_expected From 806252f9d9bcf66dbac3e3d6443baea8030b17f7 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 7 Aug 2023 16:34:03 +0300 Subject: [PATCH 003/135] prototype --- contracts/counter/Cargo.toml | 3 + contracts/counter/examples/cli.rs | 13 ++++ contracts/counter/src/msg.rs | 3 + cw-orch/Cargo.toml | 6 ++ cw-orch/src/lib.rs | 1 + packages/cw-orch-cli-derive/Cargo.toml | 18 +++++ packages/cw-orch-cli-derive/src/lib.rs | 16 +++++ packages/cw-orch-cli/Cargo.toml | 22 ++++++ packages/cw-orch-cli/GUIDE.md | 17 +++++ packages/cw-orch-cli/README.md | 3 + packages/cw-orch-cli/src/lib.rs | 93 ++++++++++++++++++++++++++ packages/cw-orch-cli/src/main.rs | 3 + 12 files changed, 198 insertions(+) create mode 100644 contracts/counter/examples/cli.rs create mode 100644 packages/cw-orch-cli-derive/Cargo.toml create mode 100644 packages/cw-orch-cli-derive/src/lib.rs create mode 100644 packages/cw-orch-cli/Cargo.toml create mode 100644 packages/cw-orch-cli/GUIDE.md create mode 100644 packages/cw-orch-cli/README.md create mode 100644 packages/cw-orch-cli/src/lib.rs create mode 100644 packages/cw-orch-cli/src/main.rs diff --git a/contracts/counter/Cargo.toml b/contracts/counter/Cargo.toml index accb2d9b6..95dd83ab1 100644 --- a/contracts/counter/Cargo.toml +++ b/contracts/counter/Cargo.toml @@ -25,6 +25,9 @@ serde = { workspace = true } serde_json = "1.0.79" cw-orch = { path = "../../cw-orch", optional = true } +strum = { version = "0.25", features = ["derive"] } +cw-orch-cli = { path = "../../packages/cw-orch-cli" } + [dev-dependencies] cw-multi-test = { workspace = true } counter-contract = { path = ".", features = ["interface"] } diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs new file mode 100644 index 000000000..b65b965a0 --- /dev/null +++ b/contracts/counter/examples/cli.rs @@ -0,0 +1,13 @@ +use counter_contract::{ + msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, + ContractError, +}; +use cw_orch::anyhow; +use cw_orch_cli::ContractCli; + +type CounterCli = ContractCli; + +pub fn main() -> anyhow::Result<()> { + CounterCli::select_action()?; + Ok(()) +} diff --git a/contracts/counter/src/msg.rs b/contracts/counter/src/msg.rs index e89b8bd58..7dc13096d 100644 --- a/contracts/counter/src/msg.rs +++ b/contracts/counter/src/msg.rs @@ -1,4 +1,6 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; +use cw_orch::cli; +pub use cw_orch_cli::strum; #[cw_serde] pub struct InstantiateMsg { @@ -7,6 +9,7 @@ pub struct InstantiateMsg { // ANCHOR: exec_msg #[cw_serde] +#[cli] #[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))] // Function generation pub enum ExecuteMsg { Increment {}, diff --git a/cw-orch/Cargo.toml b/cw-orch/Cargo.toml index 4688396f0..3a38c15b0 100644 --- a/cw-orch/Cargo.toml +++ b/cw-orch/Cargo.toml @@ -66,6 +66,12 @@ osmosis-test-tube = ["dep:osmosis-test-tube"] # Default deps cw-orch-contract-derive = { path = "../packages/cw-orch-contract-derive", version = "0.13.3" } cw-orch-fns-derive = { path = "../packages/cw-orch-fns-derive", version = "0.13.3" } +cw-orch-cli-derive = { path = "../packages/cw-orch-cli-derive", version = "0.13.3" } +interactive-clap = "0.2.4" +clap = { version = "4.0.18", features = ["derive"] } +color-eyre = { version = "0.6" } +inquire = { version = "0.6" } +strum = { version = "0.25", features = ["derive"] } cosmwasm-std = { workspace = true } cw-utils = { workspace = true } diff --git a/cw-orch/src/lib.rs b/cw-orch/src/lib.rs index 71f338578..432d735a1 100644 --- a/cw-orch/src/lib.rs +++ b/cw-orch/src/lib.rs @@ -3,6 +3,7 @@ #![deny(missing_docs)] // macros +pub use cw_orch_cli_derive::cli; pub use cw_orch_contract_derive::{interface, interface_entry_point}; pub use cw_orch_fns_derive::{ExecuteFns, QueryFns}; diff --git a/packages/cw-orch-cli-derive/Cargo.toml b/packages/cw-orch-cli-derive/Cargo.toml new file mode 100644 index 000000000..e6f5c1d75 --- /dev/null +++ b/packages/cw-orch-cli-derive/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "cw-orch-cli-derive" +version = "0.13.3" +authors = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +description = "Derive macro for generating cli interface." + +[lib] +proc-macro = true + +[dependencies] +quote = "1" +proc-macro2 = "1" +syn = { version = "1", features = ["full", "extra-traits", "visit-mut"] } +convert_case = "0.6.0" +interactive-clap = "0.2.4" \ No newline at end of file diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs new file mode 100644 index 000000000..e339bbc14 --- /dev/null +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -0,0 +1,16 @@ +use proc_macro::TokenStream; +extern crate proc_macro; +use quote::quote; + +// TODO: check what's the best way to serialize for user +#[proc_macro_attribute] +pub fn cli(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input: proc_macro2::TokenStream = item.into(); + let output = quote! { + #[derive(::cw_orch_cli::strum::EnumDiscriminants, ::cw_orch_cli::strum::EnumIter, ::cw_orch_cli::strum::EnumVariantNames)] + #[strum(serialize_all = "snake_case")] + #[strum(crate = "::cw_orch_cli::strum")] + #input + }; + output.into() +} diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml new file mode 100644 index 000000000..e9fdae750 --- /dev/null +++ b/packages/cw-orch-cli/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "cw-orch-cli" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cosmwasm-std = { workspace = true } +cw-orch = { path = "../../cw-orch" } +cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } +interactive-clap = "0.2.4" +clap = { version = "4.0.18", features = ["derive"] } +color-eyre = { version = "0.6" } +inquire = { version = "0.6" } +strum = { version = "0.25", features = ["derive"] } + +serde_json = "1.0.79" +serde = { workspace = true } \ No newline at end of file diff --git a/packages/cw-orch-cli/GUIDE.md b/packages/cw-orch-cli/GUIDE.md new file mode 100644 index 000000000..d28e9b27b --- /dev/null +++ b/packages/cw-orch-cli/GUIDE.md @@ -0,0 +1,17 @@ +## User Guide +Before deciding what command you want to run you'll have to: +1. Chose one of the supported chains by the cw-orch. +2. Select signing method (optionally) + +### Command groups + +- wasm - Deploy, Instantiate, Query, Execute, Migrate smart contracts +- TODO?:bank - send coins, query bank balances, denom metadata. + +#### Wasm subcommands +- execute +- query (Signer not required) +- instantiate +- deploy +- migrate + diff --git a/packages/cw-orch-cli/README.md b/packages/cw-orch-cli/README.md new file mode 100644 index 000000000..2801217fa --- /dev/null +++ b/packages/cw-orch-cli/README.md @@ -0,0 +1,3 @@ +## Cw Orch CLI + +Cw Orch CLI is a command line utility for working with cosmos blockhains diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs new file mode 100644 index 000000000..258fe64f1 --- /dev/null +++ b/packages/cw-orch-cli/src/lib.rs @@ -0,0 +1,93 @@ +pub use strum; + +use std::marker::PhantomData; + +use inquire::{ui::RenderConfig, CustomType}; +use serde::{de::DeserializeOwned, Serialize}; +use strum::{EnumIter, IntoEnumIterator, VariantNames}; + +pub trait ContractError: From + 'static {} + +impl ContractError for T where T: From + 'static {} + +#[derive(EnumIter)] +pub enum ActionVariants { + Execute, + Query, + Instantiate, + Migrate, +} + +impl std::fmt::Display for ActionVariants { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ActionVariants::Execute => write!(f, "execute"), + ActionVariants::Query => write!(f, "query"), + ActionVariants::Instantiate => write!(f, "instantiate"), + ActionVariants::Migrate => write!(f, "migrate"), + } + } +} + +pub struct ContractCli< + Error: ContractError, + CustomInitMsg: Clone + Serialize + DeserializeOwned + 'static, + CustomExecMsg: Clone + Serialize + DeserializeOwned + VariantNames + 'static, + CustomQueryMsg: Clone + Serialize + DeserializeOwned + 'static, + CustomMigrateMsg: Clone + Serialize + DeserializeOwned + 'static, +> { + pub(crate) init: PhantomData, + pub(crate) exec: PhantomData, + pub(crate) query: PhantomData, + pub(crate) migrate: PhantomData, + pub(crate) error: PhantomData, +} + +impl< + Error: ContractError, + CustomInitMsg: Clone + Serialize + DeserializeOwned + 'static, + CustomExecMsg: Clone + Serialize + DeserializeOwned + VariantNames + 'static, + CustomQueryMsg: Clone + Serialize + DeserializeOwned + 'static, + CustomMigrateMsg: Clone + Serialize + DeserializeOwned + 'static, + > ContractCli +{ + pub fn select_action() -> cw_orch::anyhow::Result<()> { + let action = + inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; + + match action { + ActionVariants::Execute => Self::execute(), + ActionVariants::Query => todo!(), + ActionVariants::Instantiate => todo!(), + ActionVariants::Migrate => todo!(), + } + } + fn execute() -> cw_orch::anyhow::Result<()> { + let variant = + inquire::Select::new("Select Execute Message", CustomExecMsg::VARIANTS.to_vec()) + .prompt()? + .to_lowercase(); + let execute_msg: CustomExecMsg = CustomType { + message: "Execute Msg", + default: None, + placeholder: Some("{\"key\": \"value\"}"), + help_message: None, + formatter: &|val: CustomExecMsg| serde_json::to_string(&val).unwrap(), + default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), + parser: &|input| { + let s = format!("{{\"{variant}\": {input}}}"); + serde_json::from_str(&s).map_err(|_| ()) + }, + validators: vec![], + error_message: "Serialization failed".to_owned(), + render_config: RenderConfig::empty(), + } + .prompt()?; + println!( + "execute_msg: {}", + serde_json::to_string(&execute_msg).unwrap() + ); + + Ok(()) + } +} diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/packages/cw-orch-cli/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 78c5e4206d4ec428abac2f6ce0a3c260933c1508 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 8 Aug 2023 13:44:50 +0300 Subject: [PATCH 004/135] small improvements --- contracts/counter/Cargo.toml | 6 ++- contracts/counter/src/msg.rs | 2 +- packages/cw-orch-cli-derive/src/lib.rs | 4 +- packages/cw-orch-cli/Cargo.toml | 2 +- packages/cw-orch-cli/src/lib.rs | 73 +++++++++++++++----------- 5 files changed, 50 insertions(+), 37 deletions(-) diff --git a/contracts/counter/Cargo.toml b/contracts/counter/Cargo.toml index 95dd83ab1..5cc0c56d0 100644 --- a/contracts/counter/Cargo.toml +++ b/contracts/counter/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib", "rlib"] [features] default = ["export"] export = [] -interface = ["dep:cw-orch"] +interface = ["dep:cw-orch", "dep:cw-orch-cli"] [dependencies] cosmwasm-std = { workspace = true } @@ -26,7 +26,8 @@ serde_json = "1.0.79" cw-orch = { path = "../../cw-orch", optional = true } strum = { version = "0.25", features = ["derive"] } -cw-orch-cli = { path = "../../packages/cw-orch-cli" } + +cw-orch-cli = { path = "../../packages/cw-orch-cli", optional = true } [dev-dependencies] cw-multi-test = { workspace = true } @@ -35,3 +36,4 @@ counter-contract = { path = ".", features = ["interface"] } dotenv = { version = "0.15.0" } env_logger = { version = "0.10.0" } cw-orch = { path = "../../cw-orch", features = ["daemon", "osmosis-test-tube"] } +cw-orch-cli = { path = "../../packages/cw-orch-cli" } diff --git a/contracts/counter/src/msg.rs b/contracts/counter/src/msg.rs index 7dc13096d..9e1e76ec9 100644 --- a/contracts/counter/src/msg.rs +++ b/contracts/counter/src/msg.rs @@ -1,6 +1,5 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cw_orch::cli; -pub use cw_orch_cli::strum; #[cw_serde] pub struct InstantiateMsg { @@ -19,6 +18,7 @@ pub enum ExecuteMsg { // ANCHOR: query_msg #[cw_serde] +#[cli] #[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] // Function generation #[derive(QueryResponses)] pub enum QueryMsg { diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index e339bbc14..9c3241d7c 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -7,7 +7,9 @@ use quote::quote; pub fn cli(_attr: TokenStream, item: TokenStream) -> TokenStream { let input: proc_macro2::TokenStream = item.into(); let output = quote! { - #[derive(::cw_orch_cli::strum::EnumDiscriminants, ::cw_orch_cli::strum::EnumIter, ::cw_orch_cli::strum::EnumVariantNames)] + #[cfg_attr(feature = "interface", derive( + ::cw_orch_cli::strum::EnumVariantNames, + ))] #[strum(serialize_all = "snake_case")] #[strum(crate = "::cw_orch_cli::strum")] #input diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index e9fdae750..b55c39e03 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true [dependencies] cosmwasm-std = { workspace = true } -cw-orch = { path = "../../cw-orch" } +cw-orch = { path = "../../cw-orch", features = ["daemon"]} cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } interactive-clap = "0.2.4" clap = { version = "4.0.18", features = ["derive"] } diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 258fe64f1..1ee17d4b8 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,40 +1,39 @@ +use cw_orch::{ + prelude::{networks::parse_network, Daemon, DaemonBuilder, TxHandler}, + tokio::runtime::Runtime, +}; pub use strum; use std::marker::PhantomData; use inquire::{ui::RenderConfig, CustomType}; use serde::{de::DeserializeOwned, Serialize}; -use strum::{EnumIter, IntoEnumIterator, VariantNames}; +use strum::{Display, EnumIter, IntoEnumIterator, VariantNames}; pub trait ContractError: From + 'static {} - impl ContractError for T where T: From + 'static {} -#[derive(EnumIter)] +pub trait ContractEnumMsg: Clone + Serialize + DeserializeOwned + VariantNames + 'static {} +impl ContractEnumMsg for T where T: Clone + Serialize + DeserializeOwned + VariantNames + 'static {} + +pub trait ContractStructMsg: Clone + Serialize + DeserializeOwned + 'static {} +impl ContractStructMsg for T where T: Clone + Serialize + DeserializeOwned + 'static {} + +#[derive(EnumIter, Display)] pub enum ActionVariants { Execute, Query, Instantiate, Migrate, -} - -impl std::fmt::Display for ActionVariants { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ActionVariants::Execute => write!(f, "execute"), - ActionVariants::Query => write!(f, "query"), - ActionVariants::Instantiate => write!(f, "instantiate"), - ActionVariants::Migrate => write!(f, "migrate"), - } - } + Quit, } pub struct ContractCli< Error: ContractError, - CustomInitMsg: Clone + Serialize + DeserializeOwned + 'static, - CustomExecMsg: Clone + Serialize + DeserializeOwned + VariantNames + 'static, - CustomQueryMsg: Clone + Serialize + DeserializeOwned + 'static, - CustomMigrateMsg: Clone + Serialize + DeserializeOwned + 'static, + CustomInitMsg: ContractStructMsg, + CustomExecMsg: ContractEnumMsg, + CustomQueryMsg: ContractEnumMsg, + CustomMigrateMsg: ContractStructMsg, > { pub(crate) init: PhantomData, pub(crate) exec: PhantomData, @@ -45,21 +44,31 @@ pub struct ContractCli< impl< Error: ContractError, - CustomInitMsg: Clone + Serialize + DeserializeOwned + 'static, - CustomExecMsg: Clone + Serialize + DeserializeOwned + VariantNames + 'static, - CustomQueryMsg: Clone + Serialize + DeserializeOwned + 'static, - CustomMigrateMsg: Clone + Serialize + DeserializeOwned + 'static, + CustomInitMsg: ContractStructMsg, + CustomExecMsg: ContractEnumMsg, + CustomQueryMsg: ContractEnumMsg, + CustomMigrateMsg: ContractStructMsg, > ContractCli { pub fn select_action() -> cw_orch::anyhow::Result<()> { - let action = - inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; - - match action { - ActionVariants::Execute => Self::execute(), - ActionVariants::Query => todo!(), - ActionVariants::Instantiate => todo!(), - ActionVariants::Migrate => todo!(), + let network = inquire::Text::new("Chain id").prompt()?; + let chain = parse_network(&network); + let rt = Runtime::new()?; + // TODO: option to change wallet + let daemon = DaemonBuilder::default() + .chain(chain) + .handle(rt.handle()) + .build()?; + loop { + let action = + inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; + match action { + ActionVariants::Execute => Self::execute()?, + ActionVariants::Query => todo!(), + ActionVariants::Instantiate => todo!(), + ActionVariants::Migrate => todo!(), + ActionVariants::Quit => return Ok(()), + } } } fn execute() -> cw_orch::anyhow::Result<()> { @@ -78,9 +87,9 @@ impl< let s = format!("{{\"{variant}\": {input}}}"); serde_json::from_str(&s).map_err(|_| ()) }, - validators: vec![], + validators: CustomType::DEFAULT_VALIDATORS, error_message: "Serialization failed".to_owned(), - render_config: RenderConfig::empty(), + render_config: RenderConfig::default_colored(), } .prompt()?; println!( From 3492e3b6060a5dddb281765d046dbb76e4bdecc1 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 8 Aug 2023 14:56:22 +0300 Subject: [PATCH 005/135] instantiate msg --- contracts/counter/examples/cli.rs | 21 +++-- packages/cw-orch-cli/Cargo.toml | 3 +- packages/cw-orch-cli/src/lib.rs | 122 +++++++++++++++++------------- 3 files changed, 87 insertions(+), 59 deletions(-) diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index b65b965a0..1f1524a2f 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -1,13 +1,24 @@ use counter_contract::{ msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, - ContractError, + ContractError, CounterContract, }; -use cw_orch::anyhow; +use cw_orch::{anyhow, tokio::runtime::Runtime, prelude::{networks, DaemonBuilder}}; use cw_orch_cli::ContractCli; -type CounterCli = ContractCli; - pub fn main() -> anyhow::Result<()> { - CounterCli::select_action()?; + dotenv::dotenv().ok(); + env_logger::init(); + + let rt = Runtime::new()?; + let network = networks::UNI_6; + let chain = DaemonBuilder::default() + .handle(rt.handle()) + .chain(network) + .build()?; + + let counter = CounterContract::new("counter_contract", chain); + + ContractCli::select_action(counter)?; + Ok(()) } diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index b55c39e03..8f7045fec 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -19,4 +19,5 @@ inquire = { version = "0.6" } strum = { version = "0.25", features = ["derive"] } serde_json = "1.0.79" -serde = { workspace = true } \ No newline at end of file +serde = { workspace = true } +log = "0.4.14" \ No newline at end of file diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 1ee17d4b8..49430f73f 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,12 +1,13 @@ use cw_orch::{ - prelude::{networks::parse_network, Daemon, DaemonBuilder, TxHandler}, - tokio::runtime::Runtime, + daemon::CosmTxResponse, + prelude::{ + ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchUpload, Daemon, + ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, + }, }; pub use strum; -use std::marker::PhantomData; - -use inquire::{ui::RenderConfig, CustomType}; +use inquire::{parser::CustomTypeParser, ui::RenderConfig, CustomType}; use serde::{de::DeserializeOwned, Serialize}; use strum::{Display, EnumIter, IntoEnumIterator, VariantNames}; @@ -23,80 +24,95 @@ impl ContractStructMsg for T where T: Clone + Serialize + DeserializeOwned + pub enum ActionVariants { Execute, Query, + Deploy, Instantiate, Migrate, Quit, } pub struct ContractCli< - Error: ContractError, - CustomInitMsg: ContractStructMsg, - CustomExecMsg: ContractEnumMsg, - CustomQueryMsg: ContractEnumMsg, - CustomMigrateMsg: ContractStructMsg, -> { - pub(crate) init: PhantomData, - pub(crate) exec: PhantomData, - pub(crate) query: PhantomData, - pub(crate) migrate: PhantomData, - pub(crate) error: PhantomData, + Contract: ContractInstance + + InstantiableContract + + ExecutableContract + + QueryableContract + + MigratableContract, +> where + ::InstantiateMsg: ContractStructMsg, + ::ExecuteMsg: ContractEnumMsg, +{ + pub(crate) contract: Contract, } impl< - Error: ContractError, - CustomInitMsg: ContractStructMsg, - CustomExecMsg: ContractEnumMsg, - CustomQueryMsg: ContractEnumMsg, - CustomMigrateMsg: ContractStructMsg, - > ContractCli + Contract: ContractInstance + + CwOrchUpload + + InstantiableContract + + ExecutableContract + + QueryableContract + + MigratableContract, + > ContractCli +where + ::InstantiateMsg: ContractStructMsg, + ::ExecuteMsg: ContractEnumMsg, { - pub fn select_action() -> cw_orch::anyhow::Result<()> { - let network = inquire::Text::new("Chain id").prompt()?; - let chain = parse_network(&network); - let rt = Runtime::new()?; - // TODO: option to change wallet - let daemon = DaemonBuilder::default() - .chain(chain) - .handle(rt.handle()) - .build()?; + pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { + let instance = ContractCli { contract }; loop { let action = inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; - match action { - ActionVariants::Execute => Self::execute()?, + let result = match action { + ActionVariants::Execute => instance.execute()?, ActionVariants::Query => todo!(), - ActionVariants::Instantiate => todo!(), + ActionVariants::Deploy => instance.contract.upload()?, + ActionVariants::Instantiate => instance.instantiate()?, ActionVariants::Migrate => todo!(), ActionVariants::Quit => return Ok(()), - } + }; + log::debug!("tx result: {result:?}") } } - fn execute() -> cw_orch::anyhow::Result<()> { - let variant = - inquire::Select::new("Select Execute Message", CustomExecMsg::VARIANTS.to_vec()) - .prompt()? - .to_lowercase(); - let execute_msg: CustomExecMsg = CustomType { + + fn instantiate(&self) -> cw_orch::anyhow::Result { + let instantiate_msg: ::InstantiateMsg = + Self::msg(&|input| serde_json::from_str(&input).map_err(|_| ()))?; + let res = self.contract.instantiate(&instantiate_msg, None, None)?; + Ok(res) + } + + fn execute(&self) -> cw_orch::anyhow::Result { + let variant = inquire::Select::new( + "Select Execute Message", + ::ExecuteMsg::VARIANTS.to_vec(), + ) + .prompt()? + .to_lowercase(); + let execute_msg: ::ExecuteMsg = Self::msg(&|input| { + let s = format!("{{\"{variant}\": {input}}}"); + serde_json::from_str(&s).map_err(|_| ()) + })?; + + // TODO: support attaching coins + let res = self.contract.execute(&execute_msg, None)?; + + Ok(res) + } + + fn msg<'a, Msg: Serialize + Clone>( + parser: CustomTypeParser<'a, Msg>, + ) -> cw_orch::anyhow::Result { + let msg = CustomType { message: "Execute Msg", default: None, placeholder: Some("{\"key\": \"value\"}"), help_message: None, - formatter: &|val: CustomExecMsg| serde_json::to_string(&val).unwrap(), + formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), - parser: &|input| { - let s = format!("{{\"{variant}\": {input}}}"); - serde_json::from_str(&s).map_err(|_| ()) - }, + parser: parser, validators: CustomType::DEFAULT_VALIDATORS, error_message: "Serialization failed".to_owned(), render_config: RenderConfig::default_colored(), } .prompt()?; - println!( - "execute_msg: {}", - serde_json::to_string(&execute_msg).unwrap() - ); - - Ok(()) + Ok(msg) } -} +} \ No newline at end of file From c4624204975e487529476996ecfc5c9949940f42 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 8 Aug 2023 16:51:02 +0300 Subject: [PATCH 006/135] migrate --- contracts/counter/examples/cli.rs | 10 +-- contracts/counter/src/msg.rs | 1 + cw-orch/src/daemon/tx_builder.rs | 2 +- packages/cw-orch-cli-derive/src/lib.rs | 29 +++++--- packages/cw-orch-cli/src/lib.rs | 95 +++++++++++++++++--------- 5 files changed, 86 insertions(+), 51 deletions(-) diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index 1f1524a2f..681815a64 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -1,13 +1,13 @@ -use counter_contract::{ - msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}, - ContractError, CounterContract, +use counter_contract::CounterContract; +use cw_orch::{ + anyhow, + prelude::{networks, DaemonBuilder}, + tokio::runtime::Runtime, }; -use cw_orch::{anyhow, tokio::runtime::Runtime, prelude::{networks, DaemonBuilder}}; use cw_orch_cli::ContractCli; pub fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); - env_logger::init(); let rt = Runtime::new()?; let network = networks::UNI_6; diff --git a/contracts/counter/src/msg.rs b/contracts/counter/src/msg.rs index 9e1e76ec9..06902eaac 100644 --- a/contracts/counter/src/msg.rs +++ b/contracts/counter/src/msg.rs @@ -2,6 +2,7 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; use cw_orch::cli; #[cw_serde] +#[cli] pub struct InstantiateMsg { pub count: i32, } diff --git a/cw-orch/src/daemon/tx_builder.rs b/cw-orch/src/daemon/tx_builder.rs index 728a7c63b..6ac872c5c 100644 --- a/cw-orch/src/daemon/tx_builder.rs +++ b/cw-orch/src/daemon/tx_builder.rs @@ -10,7 +10,7 @@ use secp256k1::All; use super::{sender::Sender, DaemonError}; const GAS_BUFFER: f64 = 1.2; -const BUFFER_CHANGE_LIMIT: u64 = 100_000; +const BUFFER_CHANGE_LIMIT: u64 = 150_000; const SMALL_GAS_BUFFER: f64 = 1.4; /// Struct used to build a raw transaction and broadcast it with a sender. diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index 9c3241d7c..dd937535b 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -1,18 +1,25 @@ use proc_macro::TokenStream; extern crate proc_macro; -use quote::quote; +use quote::ToTokens; +use syn::{parse_macro_input, parse_quote, DeriveInput}; // TODO: check what's the best way to serialize for user #[proc_macro_attribute] -pub fn cli(_attr: TokenStream, item: TokenStream) -> TokenStream { - let input: proc_macro2::TokenStream = item.into(); - let output = quote! { - #[cfg_attr(feature = "interface", derive( - ::cw_orch_cli::strum::EnumVariantNames, - ))] - #[strum(serialize_all = "snake_case")] - #[strum(crate = "::cw_orch_cli::strum")] - #input +pub fn cli(_attr: TokenStream, input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let output: DeriveInput = match input.data { + syn::Data::Struct(_) => parse_quote!(#input), + syn::Data::Enum(_) => { + parse_quote!( + #[cfg_attr(feature = "interface", derive( + ::cw_orch_cli::strum::EnumVariantNames, + ))] + #[strum(serialize_all = "snake_case")] + #[strum(crate = "::cw_orch_cli::strum")] + #input + ) + } + syn::Data::Union(_) => parse_quote!(#input), }; - output.into() + TokenStream::from(output.into_token_stream()) } diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 49430f73f..db4dbfb1a 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,9 +1,6 @@ -use cw_orch::{ - daemon::CosmTxResponse, - prelude::{ - ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchUpload, Daemon, - ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, - }, +use cw_orch::prelude::{ + ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, + Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, }; pub use strum; @@ -43,71 +40,101 @@ pub struct ContractCli< pub(crate) contract: Contract, } -impl< - Contract: ContractInstance - + CwOrchUpload - + InstantiableContract - + ExecutableContract - + QueryableContract - + MigratableContract, - > ContractCli +impl ContractCli where + Contract: ContractInstance + + CwOrchUpload + + InstantiableContract + + ExecutableContract + + QueryableContract + + MigratableContract, ::InstantiateMsg: ContractStructMsg, ::ExecuteMsg: ContractEnumMsg, + ::QueryMsg: ContractEnumMsg, + ::MigrateMsg: ContractStructMsg, { pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { let instance = ContractCli { contract }; loop { let action = inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; - let result = match action { + match action { ActionVariants::Execute => instance.execute()?, - ActionVariants::Query => todo!(), - ActionVariants::Deploy => instance.contract.upload()?, + ActionVariants::Query => instance.query()?, + ActionVariants::Deploy => instance.contract.upload().map(|_| ())?, ActionVariants::Instantiate => instance.instantiate()?, - ActionVariants::Migrate => todo!(), + ActionVariants::Migrate => instance.migrate()?, ActionVariants::Quit => return Ok(()), - }; - log::debug!("tx result: {result:?}") + } } } - fn instantiate(&self) -> cw_orch::anyhow::Result { + fn instantiate(&self) -> cw_orch::anyhow::Result<()> { let instantiate_msg: ::InstantiateMsg = - Self::msg(&|input| serde_json::from_str(&input).map_err(|_| ()))?; - let res = self.contract.instantiate(&instantiate_msg, None, None)?; - Ok(res) + Self::msg("Instantiate Message", &|input| { + serde_json::from_str(&input).map_err(|_| ()) + })?; + self.contract.instantiate(&instantiate_msg, None, None)?; + Ok(()) } - fn execute(&self) -> cw_orch::anyhow::Result { + fn execute(&self) -> cw_orch::anyhow::Result<()> { let variant = inquire::Select::new( "Select Execute Message", ::ExecuteMsg::VARIANTS.to_vec(), ) .prompt()? .to_lowercase(); - let execute_msg: ::ExecuteMsg = Self::msg(&|input| { - let s = format!("{{\"{variant}\": {input}}}"); - serde_json::from_str(&s).map_err(|_| ()) - })?; + let execute_msg: ::ExecuteMsg = + Self::msg("Execute Message", &|input| { + let s = format!("{{\"{variant}\": {input}}}"); + serde_json::from_str(&s).map_err(|_| ()) + })?; // TODO: support attaching coins - let res = self.contract.execute(&execute_msg, None)?; + self.contract.execute(&execute_msg, None)?; - Ok(res) + Ok(()) + } + + fn query(&self) -> cw_orch::anyhow::Result<()> { + let variant = inquire::Select::new( + "Select Query Message", + ::QueryMsg::VARIANTS.to_vec(), + ) + .prompt()?; + let query_msg: ::QueryMsg = + Self::msg("Query Message", &|input| { + let s = format!("{{\"{variant}\": {input}}}"); + serde_json::from_str(&s).map_err(|_| ()) + })?; + let resp: serde_json::Value = self.contract.query(&query_msg)?; + println!("{}", serde_json::to_string_pretty(&resp)?); + Ok(()) + } + + fn migrate(&self) -> cw_orch::anyhow::Result<()> { + let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; + let migrate_msg: ::MigrateMsg = + Self::msg("Migrate Message", &|input| { + serde_json::from_str(&input).map_err(|_| ()) + })?; + self.contract.migrate(&migrate_msg, new_code_id)?; + Ok(()) } fn msg<'a, Msg: Serialize + Clone>( + message: &str, parser: CustomTypeParser<'a, Msg>, ) -> cw_orch::anyhow::Result { let msg = CustomType { - message: "Execute Msg", + message, default: None, placeholder: Some("{\"key\": \"value\"}"), help_message: None, formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), - parser: parser, + parser, validators: CustomType::DEFAULT_VALIDATORS, error_message: "Serialization failed".to_owned(), render_config: RenderConfig::default_colored(), @@ -115,4 +142,4 @@ where .prompt()?; Ok(msg) } -} \ No newline at end of file +} From 15981805baf8745cf7aa2f286e0769601b7af57d Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 8 Aug 2023 19:40:14 +0300 Subject: [PATCH 007/135] small refactor --- packages/cw-orch-cli-derive/src/lib.rs | 8 ++++---- packages/cw-orch-cli/src/lib.rs | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index dd937535b..6deb4006a 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -3,7 +3,6 @@ extern crate proc_macro; use quote::ToTokens; use syn::{parse_macro_input, parse_quote, DeriveInput}; -// TODO: check what's the best way to serialize for user #[proc_macro_attribute] pub fn cli(_attr: TokenStream, input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -11,9 +10,10 @@ pub fn cli(_attr: TokenStream, input: TokenStream) -> TokenStream { syn::Data::Struct(_) => parse_quote!(#input), syn::Data::Enum(_) => { parse_quote!( - #[cfg_attr(feature = "interface", derive( - ::cw_orch_cli::strum::EnumVariantNames, - ))] + #[cfg_attr( + not(target_arch = "wasm32"), + derive(::cw_orch_cli::strum::EnumVariantNames) + )] #[strum(serialize_all = "snake_case")] #[strum(crate = "::cw_orch_cli::strum")] #input diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index db4dbfb1a..b80587559 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -61,7 +61,10 @@ where match action { ActionVariants::Execute => instance.execute()?, ActionVariants::Query => instance.query()?, - ActionVariants::Deploy => instance.contract.upload().map(|_| ())?, + ActionVariants::Deploy => { + instance.contract.upload()?; + println!("Code_id: {}", instance.contract.addr_str()?); + }, ActionVariants::Instantiate => instance.instantiate()?, ActionVariants::Migrate => instance.migrate()?, ActionVariants::Quit => return Ok(()), @@ -75,6 +78,7 @@ where serde_json::from_str(&input).map_err(|_| ()) })?; self.contract.instantiate(&instantiate_msg, None, None)?; + println!("Instantiation succesfull"); Ok(()) } From 0b546144bec773fb1e9baa67bf502877eb1f8105 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 10 Aug 2023 17:48:20 +0300 Subject: [PATCH 008/135] Parse fields --- contracts/counter/src/msg.rs | 8 +- cw-orch/Cargo.toml | 1 - cw-orch/src/lib.rs | 1 - packages/cw-orch-cli-derive/src/lib.rs | 132 +++++++++++++++++++++---- packages/cw-orch-cli/src/lib.rs | 102 +++++++++---------- 5 files changed, 162 insertions(+), 82 deletions(-) diff --git a/contracts/counter/src/msg.rs b/contracts/counter/src/msg.rs index 06902eaac..cfc57a26c 100644 --- a/contracts/counter/src/msg.rs +++ b/contracts/counter/src/msg.rs @@ -1,15 +1,14 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; -use cw_orch::cli; #[cw_serde] -#[cli] +#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] pub struct InstantiateMsg { pub count: i32, } // ANCHOR: exec_msg #[cw_serde] -#[cli] +#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] #[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))] // Function generation pub enum ExecuteMsg { Increment {}, @@ -19,7 +18,7 @@ pub enum ExecuteMsg { // ANCHOR: query_msg #[cw_serde] -#[cli] +#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] #[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] // Function generation #[derive(QueryResponses)] pub enum QueryMsg { @@ -36,6 +35,7 @@ pub struct GetCountResponse { // ANCHOR_END: query_msg #[cw_serde] +#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] pub struct MigrateMsg { pub t: String, } diff --git a/cw-orch/Cargo.toml b/cw-orch/Cargo.toml index 3a38c15b0..961fe2ecd 100644 --- a/cw-orch/Cargo.toml +++ b/cw-orch/Cargo.toml @@ -66,7 +66,6 @@ osmosis-test-tube = ["dep:osmosis-test-tube"] # Default deps cw-orch-contract-derive = { path = "../packages/cw-orch-contract-derive", version = "0.13.3" } cw-orch-fns-derive = { path = "../packages/cw-orch-fns-derive", version = "0.13.3" } -cw-orch-cli-derive = { path = "../packages/cw-orch-cli-derive", version = "0.13.3" } interactive-clap = "0.2.4" clap = { version = "4.0.18", features = ["derive"] } color-eyre = { version = "0.6" } diff --git a/cw-orch/src/lib.rs b/cw-orch/src/lib.rs index 432d735a1..71f338578 100644 --- a/cw-orch/src/lib.rs +++ b/cw-orch/src/lib.rs @@ -3,7 +3,6 @@ #![deny(missing_docs)] // macros -pub use cw_orch_cli_derive::cli; pub use cw_orch_contract_derive::{interface, interface_entry_point}; pub use cw_orch_fns_derive::{ExecuteFns, QueryFns}; diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index 6deb4006a..c2cbe1dc3 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -1,25 +1,119 @@ use proc_macro::TokenStream; extern crate proc_macro; -use quote::ToTokens; -use syn::{parse_macro_input, parse_quote, DeriveInput}; +use quote::quote; +use syn::{parse_macro_input, DeriveInput, FieldsNamed}; -#[proc_macro_attribute] -pub fn cli(_attr: TokenStream, input: TokenStream) -> TokenStream { +#[proc_macro_derive(ParseCwMsg)] +pub fn derive_parse_cw_message(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - let output: DeriveInput = match input.data { - syn::Data::Struct(_) => parse_quote!(#input), - syn::Data::Enum(_) => { - parse_quote!( - #[cfg_attr( - not(target_arch = "wasm32"), - derive(::cw_orch_cli::strum::EnumVariantNames) - )] - #[strum(serialize_all = "snake_case")] - #[strum(crate = "::cw_orch_cli::strum")] - #input - ) + parse_fn_derive(input) +} + +fn parse_fn_derive(input: DeriveInput) -> TokenStream { + let name = &input.ident; + match &input.data { + syn::Data::Struct(data) => { + let syn::Fields::Named(FieldsNamed { named, .. }) = data.fields.clone() else { + unimplemented!() + }; + let fields = named.into_iter().map(|field| { + let ident = field.ident.unwrap(); + let ty = field.ty; + let message = format!("{}({})", ident, quote!(#ty).to_string()); + quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) + }); + let derived_trait_impl = quote!( + #[automatically_derived] + impl ::cw_orch_cli::ParseCwMsg for #name { + fn parse() -> ::cw_orch::anyhow::Result { + Ok(Self { + #(#fields),* + }) + } + } + ); + derived_trait_impl.into() + } + syn::Data::Enum(data) => { + let idents: Vec<_> = data.variants.iter().map(|variant| &variant.ident).collect(); + let enum_variants_ident = + proc_macro2::Ident::new(&format!("{name}Variants"), name.span()); + let enum_of_variant_names = quote!( + enum #enum_variants_ident { + #(#idents),* + } + ); + let display_for_enum_variant_names = idents.iter().map(|&ident| { + let name = ident.to_string().to_lowercase(); + quote!( + #enum_variants_ident::#ident => f.pad(#name) + ) + }); + let display_for_enum_variant_names = quote!( + impl ::std::fmt::Display for #enum_variants_ident { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + #(#display_for_enum_variant_names),* + } + } + } + ); + let variants_as_structs = data.variants.iter().map(|variant| { + let struct_name = &variant.ident; + let fields = &variant.fields; + let into_enum = quote!( + impl From<#struct_name> for #name { + fn from(val: #struct_name) -> Self { + let #struct_name #fields = val; + #name::#struct_name + #fields + + } + } + ); + let sub_fields = fields.iter().map(|field| { + let ident = field.ident.clone().unwrap(); + let ty = &field.ty; + let message = format!("{}({})", ident, quote!(#ty).to_string()); + quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) + }); + let sub_derived_trait_impl = quote!( + #[automatically_derived] + impl ::cw_orch_cli::ParseCwMsg for #struct_name { + fn parse() -> ::cw_orch::anyhow::Result { + Ok(Self { + #(#sub_fields),* + }) + } + } + ); + quote!( + struct #struct_name + #fields + #into_enum + #sub_derived_trait_impl + ) + }); + let derived_trait_impl = quote!( + #[automatically_derived] + impl ::cw_orch_cli::ParseCwMsg for #name { + fn parse() -> ::cw_orch::anyhow::Result { + #enum_of_variant_names + #display_for_enum_variant_names + let options = vec![#(#enum_variants_ident::#idents),*]; + let variant = ::cw_orch_cli::select_msg(options)?; + #(#variants_as_structs)* + let msg = match variant { + #(#enum_variants_ident:: #idents => #idents::parse()?.into()),* + }; + Ok(msg) + } + } + ); + derived_trait_impl.into() + } + syn::Data::Union(_) => { + unimplemented!() } - syn::Data::Union(_) => parse_quote!(#input), - }; - TokenStream::from(output.into_token_stream()) + } } diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index b80587559..3e12a5a40 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,10 +1,13 @@ +use std::fmt::Display; + use cw_orch::prelude::{ ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, }; +pub use cw_orch_cli_derive::ParseCwMsg; pub use strum; -use inquire::{parser::CustomTypeParser, ui::RenderConfig, CustomType}; +use inquire::{ui::RenderConfig, CustomType}; use serde::{de::DeserializeOwned, Serialize}; use strum::{Display, EnumIter, IntoEnumIterator, VariantNames}; @@ -33,10 +36,7 @@ pub struct ContractCli< + ExecutableContract + QueryableContract + MigratableContract, -> where - ::InstantiateMsg: ContractStructMsg, - ::ExecuteMsg: ContractEnumMsg, -{ +> { pub(crate) contract: Contract, } @@ -48,10 +48,10 @@ where + ExecutableContract + QueryableContract + MigratableContract, - ::InstantiateMsg: ContractStructMsg, - ::ExecuteMsg: ContractEnumMsg, - ::QueryMsg: ContractEnumMsg, - ::MigrateMsg: ContractStructMsg, + ::InstantiateMsg: ParseCwMsg, + ::ExecuteMsg: ParseCwMsg, + ::QueryMsg: ParseCwMsg, + ::MigrateMsg: ParseCwMsg, { pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { let instance = ContractCli { contract }; @@ -64,7 +64,7 @@ where ActionVariants::Deploy => { instance.contract.upload()?; println!("Code_id: {}", instance.contract.addr_str()?); - }, + } ActionVariants::Instantiate => instance.instantiate()?, ActionVariants::Migrate => instance.migrate()?, ActionVariants::Quit => return Ok(()), @@ -73,27 +73,14 @@ where } fn instantiate(&self) -> cw_orch::anyhow::Result<()> { - let instantiate_msg: ::InstantiateMsg = - Self::msg("Instantiate Message", &|input| { - serde_json::from_str(&input).map_err(|_| ()) - })?; + let instantiate_msg = ::InstantiateMsg::parse()?; self.contract.instantiate(&instantiate_msg, None, None)?; println!("Instantiation succesfull"); Ok(()) } fn execute(&self) -> cw_orch::anyhow::Result<()> { - let variant = inquire::Select::new( - "Select Execute Message", - ::ExecuteMsg::VARIANTS.to_vec(), - ) - .prompt()? - .to_lowercase(); - let execute_msg: ::ExecuteMsg = - Self::msg("Execute Message", &|input| { - let s = format!("{{\"{variant}\": {input}}}"); - serde_json::from_str(&s).map_err(|_| ()) - })?; + let execute_msg = ::ExecuteMsg::parse()?; // TODO: support attaching coins self.contract.execute(&execute_msg, None)?; @@ -102,16 +89,8 @@ where } fn query(&self) -> cw_orch::anyhow::Result<()> { - let variant = inquire::Select::new( - "Select Query Message", - ::QueryMsg::VARIANTS.to_vec(), - ) - .prompt()?; - let query_msg: ::QueryMsg = - Self::msg("Query Message", &|input| { - let s = format!("{{\"{variant}\": {input}}}"); - serde_json::from_str(&s).map_err(|_| ()) - })?; + let query_msg = ::QueryMsg::parse()?; + let resp: serde_json::Value = self.contract.query(&query_msg)?; println!("{}", serde_json::to_string_pretty(&resp)?); Ok(()) @@ -119,31 +98,40 @@ where fn migrate(&self) -> cw_orch::anyhow::Result<()> { let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; - let migrate_msg: ::MigrateMsg = - Self::msg("Migrate Message", &|input| { - serde_json::from_str(&input).map_err(|_| ()) - })?; + let migrate_msg = ::MigrateMsg::parse()?; self.contract.migrate(&migrate_msg, new_code_id)?; Ok(()) } +} - fn msg<'a, Msg: Serialize + Clone>( - message: &str, - parser: CustomTypeParser<'a, Msg>, - ) -> cw_orch::anyhow::Result { - let msg = CustomType { - message, - default: None, - placeholder: Some("{\"key\": \"value\"}"), - help_message: None, - formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), - default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), - parser, - validators: CustomType::DEFAULT_VALIDATORS, - error_message: "Serialization failed".to_owned(), - render_config: RenderConfig::default_colored(), - } - .prompt()?; - Ok(msg) +pub fn custom_type_serialize<'a, Msg: Serialize + DeserializeOwned + Clone>( + message: &str, +) -> cw_orch::anyhow::Result { + let msg = CustomType { + message, + default: None, + placeholder: None, + help_message: None, + formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), + default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), + parser: &|input| serde_json::from_str(&input).map_err(|_| ()), + validators: CustomType::DEFAULT_VALIDATORS, + error_message: "Serialization failed".to_owned(), + render_config: RenderConfig::default_colored(), } + .prompt()?; + + Ok(msg) +} + +pub fn select_msg(options: Vec) -> cw_orch::anyhow::Result { + let variant = inquire::Select::new("Select Message", options).prompt()?; + Ok(variant) +} + +pub trait ParseCwMsg +where + Self: Sized, +{ + fn parse() -> cw_orch::anyhow::Result; } From fd9ca60394473319739a1ae5fea4dc42d007a9fe Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 11 Aug 2023 13:02:58 +0300 Subject: [PATCH 009/135] small refactor --- packages/cw-orch-cli-derive/src/lib.rs | 80 ++++++++++++-------------- packages/cw-orch-cli/src/lib.rs | 11 +--- 2 files changed, 38 insertions(+), 53 deletions(-) diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index c2cbe1dc3..52c0e56e1 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -1,7 +1,8 @@ +use convert_case::Casing; use proc_macro::TokenStream; extern crate proc_macro; use quote::quote; -use syn::{parse_macro_input, DeriveInput, FieldsNamed}; +use syn::{parse_macro_input, DeriveInput, FieldsNamed, Fields}; #[proc_macro_derive(ParseCwMsg)] pub fn derive_parse_cw_message(input: TokenStream) -> TokenStream { @@ -13,29 +14,11 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { let name = &input.ident; match &input.data { syn::Data::Struct(data) => { - let syn::Fields::Named(FieldsNamed { named, .. }) = data.fields.clone() else { - unimplemented!() - }; - let fields = named.into_iter().map(|field| { - let ident = field.ident.unwrap(); - let ty = field.ty; - let message = format!("{}({})", ident, quote!(#ty).to_string()); - quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) - }); - let derived_trait_impl = quote!( - #[automatically_derived] - impl ::cw_orch_cli::ParseCwMsg for #name { - fn parse() -> ::cw_orch::anyhow::Result { - Ok(Self { - #(#fields),* - }) - } - } - ); - derived_trait_impl.into() + impl_parse_for_struct(&data.fields, name) } syn::Data::Enum(data) => { let idents: Vec<_> = data.variants.iter().map(|variant| &variant.ident).collect(); + // Generate helper enum let enum_variants_ident = proc_macro2::Ident::new(&format!("{name}Variants"), name.span()); let enum_of_variant_names = quote!( @@ -44,7 +27,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { } ); let display_for_enum_variant_names = idents.iter().map(|&ident| { - let name = ident.to_string().to_lowercase(); + let name = ident.to_string().to_case(convert_case::Case::Snake); quote!( #enum_variants_ident::#ident => f.pad(#name) ) @@ -58,6 +41,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { } } ); + let variants_as_structs = data.variants.iter().map(|variant| { let struct_name = &variant.ident; let fields = &variant.fields; @@ -71,22 +55,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { } } ); - let sub_fields = fields.iter().map(|field| { - let ident = field.ident.clone().unwrap(); - let ty = &field.ty; - let message = format!("{}({})", ident, quote!(#ty).to_string()); - quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) - }); - let sub_derived_trait_impl = quote!( - #[automatically_derived] - impl ::cw_orch_cli::ParseCwMsg for #struct_name { - fn parse() -> ::cw_orch::anyhow::Result { - Ok(Self { - #(#sub_fields),* - }) - } - } - ); + let sub_derived_trait_impl = impl_parse_for_struct(fields, struct_name); quote!( struct #struct_name #fields @@ -94,7 +63,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { #sub_derived_trait_impl ) }); - let derived_trait_impl = quote!( + quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { fn parse() -> ::cw_orch::anyhow::Result { @@ -104,16 +73,41 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { let variant = ::cw_orch_cli::select_msg(options)?; #(#variants_as_structs)* let msg = match variant { - #(#enum_variants_ident:: #idents => #idents::parse()?.into()),* + #(#enum_variants_ident::#idents => #idents::parse()?.into()),* }; Ok(msg) } } - ); - derived_trait_impl.into() + ) } syn::Data::Union(_) => { unimplemented!() } - } + }.into() +} + +fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_macro2::TokenStream { + let syn::Fields::Named(FieldsNamed { + named, + .. + }) = fields else { + unimplemented!() + }; + let fields = named.into_iter().map(|field| { + let ident = field.ident.clone().unwrap(); + let ty = field.ty.clone(); + let message = format!("{}({})", ident, quote!(#ty).to_string()); + quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) + }); + let derived_trait_impl = quote!( + #[automatically_derived] + impl ::cw_orch_cli::ParseCwMsg for #name { + fn parse() -> ::cw_orch::anyhow::Result { + Ok(Self { + #(#fields),* + }) + } + } + ); + derived_trait_impl } diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 3e12a5a40..abe94c72b 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -9,16 +9,7 @@ pub use strum; use inquire::{ui::RenderConfig, CustomType}; use serde::{de::DeserializeOwned, Serialize}; -use strum::{Display, EnumIter, IntoEnumIterator, VariantNames}; - -pub trait ContractError: From + 'static {} -impl ContractError for T where T: From + 'static {} - -pub trait ContractEnumMsg: Clone + Serialize + DeserializeOwned + VariantNames + 'static {} -impl ContractEnumMsg for T where T: Clone + Serialize + DeserializeOwned + VariantNames + 'static {} - -pub trait ContractStructMsg: Clone + Serialize + DeserializeOwned + 'static {} -impl ContractStructMsg for T where T: Clone + Serialize + DeserializeOwned + 'static {} +use strum::{Display, EnumIter, IntoEnumIterator}; #[derive(EnumIter, Display)] pub enum ActionVariants { From ac9fd99208702e357519524e30a4af4d3426ba05 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 11 Aug 2023 14:16:49 +0300 Subject: [PATCH 010/135] lints --- packages/cw-orch-cli-derive/src/lib.rs | 17 ++- packages/cw-orch-cli/src/contract/mod.rs | 130 ++++++++++++++++++++++ packages/cw-orch-cli/src/lib.rs | 132 ++--------------------- 3 files changed, 145 insertions(+), 134 deletions(-) create mode 100644 packages/cw-orch-cli/src/contract/mod.rs diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index 52c0e56e1..e597ae515 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -2,7 +2,7 @@ use convert_case::Casing; use proc_macro::TokenStream; extern crate proc_macro; use quote::quote; -use syn::{parse_macro_input, DeriveInput, FieldsNamed, Fields}; +use syn::{parse_macro_input, DeriveInput, Fields, FieldsNamed}; #[proc_macro_derive(ParseCwMsg)] pub fn derive_parse_cw_message(input: TokenStream) -> TokenStream { @@ -13,9 +13,7 @@ pub fn derive_parse_cw_message(input: TokenStream) -> TokenStream { fn parse_fn_derive(input: DeriveInput) -> TokenStream { let name = &input.ident; match &input.data { - syn::Data::Struct(data) => { - impl_parse_for_struct(&data.fields, name) - } + syn::Data::Struct(data) => impl_parse_for_struct(&data.fields, name), syn::Data::Enum(data) => { let idents: Vec<_> = data.variants.iter().map(|variant| &variant.ident).collect(); // Generate helper enum @@ -41,7 +39,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { } } ); - + let variants_as_structs = data.variants.iter().map(|variant| { let struct_name = &variant.ident; let fields = &variant.fields; @@ -83,20 +81,21 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { syn::Data::Union(_) => { unimplemented!() } - }.into() + } + .into() } fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_macro2::TokenStream { - let syn::Fields::Named(FieldsNamed { + let syn::Fields::Named(FieldsNamed { named, - .. + .. }) = fields else { unimplemented!() }; let fields = named.into_iter().map(|field| { let ident = field.ident.clone().unwrap(); let ty = field.ty.clone(); - let message = format!("{}({})", ident, quote!(#ty).to_string()); + let message = format!("{}({})", ident, quote!(#ty)); quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) }); let derived_trait_impl = quote!( diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs new file mode 100644 index 000000000..9cae54b35 --- /dev/null +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -0,0 +1,130 @@ +use std::fmt::Display; + +use cw_orch::prelude::{ + ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, + Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, +}; + +use inquire::{ui::RenderConfig, CustomType}; +use serde::{de::DeserializeOwned, Serialize}; +use strum::{Display, EnumIter, IntoEnumIterator}; + +#[derive(EnumIter, Display)] +enum ActionVariants { + Execute, + Query, + Deploy, + Instantiate, + Migrate, + Quit, +} + +pub struct ContractCli< + Contract: ContractInstance + + InstantiableContract + + ExecutableContract + + QueryableContract + + MigratableContract, +> { + pub(crate) contract: Contract, +} + +pub trait ParseCwMsg +where + Self: Sized, +{ + fn parse() -> cw_orch::anyhow::Result; +} + +impl ContractCli +where + Contract: ContractInstance + + CwOrchUpload + + InstantiableContract + + ExecutableContract + + QueryableContract + + MigratableContract, + ::InstantiateMsg: ParseCwMsg, + ::ExecuteMsg: ParseCwMsg, + ::QueryMsg: ParseCwMsg, + ::MigrateMsg: ParseCwMsg, +{ + pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { + let instance = ContractCli { contract }; + loop { + let action = + inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; + match action { + ActionVariants::Execute => instance.execute()?, + ActionVariants::Query => instance.query()?, + ActionVariants::Deploy => { + instance.contract.upload()?; + println!("Code_id: {}", instance.contract.addr_str()?); + } + ActionVariants::Instantiate => instance.instantiate()?, + ActionVariants::Migrate => instance.migrate()?, + ActionVariants::Quit => return Ok(()), + } + } + } + + fn instantiate(&self) -> cw_orch::anyhow::Result<()> { + let instantiate_msg = ::InstantiateMsg::parse()?; + self.contract.instantiate(&instantiate_msg, None, None)?; + println!("Instantiation succesfull"); + Ok(()) + } + + fn execute(&self) -> cw_orch::anyhow::Result<()> { + let execute_msg = ::ExecuteMsg::parse()?; + + // TODO: support attaching coins + self.contract.execute(&execute_msg, None)?; + + Ok(()) + } + + fn query(&self) -> cw_orch::anyhow::Result<()> { + let query_msg = ::QueryMsg::parse()?; + + let resp: serde_json::Value = self.contract.query(&query_msg)?; + println!("{}", serde_json::to_string_pretty(&resp)?); + Ok(()) + } + + fn migrate(&self) -> cw_orch::anyhow::Result<()> { + let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; + let migrate_msg = ::MigrateMsg::parse()?; + self.contract.migrate(&migrate_msg, new_code_id)?; + Ok(()) + } +} + +pub mod helpers { + use super::*; + + pub fn custom_type_serialize( + message: &str, + ) -> cw_orch::anyhow::Result { + let msg = CustomType { + message, + default: None, + placeholder: None, + help_message: None, + formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), + default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), + parser: &|input| serde_json::from_str(input).map_err(|_| ()), + validators: CustomType::DEFAULT_VALIDATORS, + error_message: "Serialization failed".to_owned(), + render_config: RenderConfig::default_colored(), + } + .prompt()?; + + Ok(msg) + } + + pub fn select_msg(options: Vec) -> cw_orch::anyhow::Result { + let variant = inquire::Select::new("Select Message", options).prompt()?; + Ok(variant) + } +} diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index abe94c72b..850859587 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,128 +1,10 @@ -use std::fmt::Display; +mod contract; -use cw_orch::prelude::{ - ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, - Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, -}; pub use cw_orch_cli_derive::ParseCwMsg; -pub use strum; - -use inquire::{ui::RenderConfig, CustomType}; -use serde::{de::DeserializeOwned, Serialize}; -use strum::{Display, EnumIter, IntoEnumIterator}; - -#[derive(EnumIter, Display)] -pub enum ActionVariants { - Execute, - Query, - Deploy, - Instantiate, - Migrate, - Quit, -} - -pub struct ContractCli< - Contract: ContractInstance - + InstantiableContract - + ExecutableContract - + QueryableContract - + MigratableContract, -> { - pub(crate) contract: Contract, -} - -impl ContractCli -where - Contract: ContractInstance - + CwOrchUpload - + InstantiableContract - + ExecutableContract - + QueryableContract - + MigratableContract, - ::InstantiateMsg: ParseCwMsg, - ::ExecuteMsg: ParseCwMsg, - ::QueryMsg: ParseCwMsg, - ::MigrateMsg: ParseCwMsg, -{ - pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { - let instance = ContractCli { contract }; - loop { - let action = - inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; - match action { - ActionVariants::Execute => instance.execute()?, - ActionVariants::Query => instance.query()?, - ActionVariants::Deploy => { - instance.contract.upload()?; - println!("Code_id: {}", instance.contract.addr_str()?); - } - ActionVariants::Instantiate => instance.instantiate()?, - ActionVariants::Migrate => instance.migrate()?, - ActionVariants::Quit => return Ok(()), - } - } - } - - fn instantiate(&self) -> cw_orch::anyhow::Result<()> { - let instantiate_msg = ::InstantiateMsg::parse()?; - self.contract.instantiate(&instantiate_msg, None, None)?; - println!("Instantiation succesfull"); - Ok(()) - } - - fn execute(&self) -> cw_orch::anyhow::Result<()> { - let execute_msg = ::ExecuteMsg::parse()?; - - // TODO: support attaching coins - self.contract.execute(&execute_msg, None)?; - Ok(()) - } - - fn query(&self) -> cw_orch::anyhow::Result<()> { - let query_msg = ::QueryMsg::parse()?; - - let resp: serde_json::Value = self.contract.query(&query_msg)?; - println!("{}", serde_json::to_string_pretty(&resp)?); - Ok(()) - } - - fn migrate(&self) -> cw_orch::anyhow::Result<()> { - let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; - let migrate_msg = ::MigrateMsg::parse()?; - self.contract.migrate(&migrate_msg, new_code_id)?; - Ok(()) - } -} - -pub fn custom_type_serialize<'a, Msg: Serialize + DeserializeOwned + Clone>( - message: &str, -) -> cw_orch::anyhow::Result { - let msg = CustomType { - message, - default: None, - placeholder: None, - help_message: None, - formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), - default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), - parser: &|input| serde_json::from_str(&input).map_err(|_| ()), - validators: CustomType::DEFAULT_VALIDATORS, - error_message: "Serialization failed".to_owned(), - render_config: RenderConfig::default_colored(), - } - .prompt()?; - - Ok(msg) -} - -pub fn select_msg(options: Vec) -> cw_orch::anyhow::Result { - let variant = inquire::Select::new("Select Message", options).prompt()?; - Ok(variant) -} - -pub trait ParseCwMsg -where - Self: Sized, -{ - fn parse() -> cw_orch::anyhow::Result; -} +pub use contract::{ + // Helpers used by derive macro + helpers::{custom_type_serialize, select_msg}, + ContractCli, + ParseCwMsg, +}; From 81e96c120221fe9aa06039085d8578172038b493 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 14 Aug 2023 16:00:37 +0300 Subject: [PATCH 011/135] Set admin and add coins --- packages/cw-orch-cli-derive/src/lib.rs | 6 +- packages/cw-orch-cli/Cargo.toml | 8 ++- packages/cw-orch-cli/src/contract/mod.rs | 82 ++++++++++++++++++++---- 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index e597ae515..91f5a5347 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -64,14 +64,14 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn parse() -> ::cw_orch::anyhow::Result { + fn cw_parse() -> ::cw_orch::anyhow::Result { #enum_of_variant_names #display_for_enum_variant_names let options = vec![#(#enum_variants_ident::#idents),*]; let variant = ::cw_orch_cli::select_msg(options)?; #(#variants_as_structs)* let msg = match variant { - #(#enum_variants_ident::#idents => #idents::parse()?.into()),* + #(#enum_variants_ident::#idents => #idents::cw_parse()?.into()),* }; Ok(msg) } @@ -101,7 +101,7 @@ fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_mac let derived_trait_impl = quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn parse() -> ::cw_orch::anyhow::Result { + fn cw_parse() -> ::cw_orch::anyhow::Result { Ok(Self { #(#fields),* }) diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 8f7045fec..0a5f87bbf 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -9,15 +9,17 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmwasm-std = { workspace = true } +cosmwasm-std = { version = "1.3"} cw-orch = { path = "../../cw-orch", features = ["daemon"]} cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } interactive-clap = "0.2.4" +interactive-clap-derive = "0.2.4" clap = { version = "4.0.18", features = ["derive"] } color-eyre = { version = "0.6" } inquire = { version = "0.6" } -strum = { version = "0.25", features = ["derive"] } +strum = { version = "0.24", features = ["derive"] } serde_json = "1.0.79" serde = { workspace = true } -log = "0.4.14" \ No newline at end of file +log = "0.4.14" +shell-words = "1.0.0" \ No newline at end of file diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index 9cae54b35..90f622c13 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -1,11 +1,12 @@ -use std::fmt::Display; +use std::fmt::{Display, Write}; +use cosmwasm_std::{Addr, Coin}; use cw_orch::prelude::{ ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, }; -use inquire::{ui::RenderConfig, CustomType}; +use inquire::{ui::RenderConfig, Confirm, CustomType, Text}; use serde::{de::DeserializeOwned, Serialize}; use strum::{Display, EnumIter, IntoEnumIterator}; @@ -33,7 +34,7 @@ pub trait ParseCwMsg where Self: Sized, { - fn parse() -> cw_orch::anyhow::Result; + fn cw_parse() -> cw_orch::anyhow::Result; } impl ContractCli @@ -69,23 +70,40 @@ where } fn instantiate(&self) -> cw_orch::anyhow::Result<()> { - let instantiate_msg = ::InstantiateMsg::parse()?; - self.contract.instantiate(&instantiate_msg, None, None)?; - println!("Instantiation succesfull"); + let instantiate_msg = ::InstantiateMsg::cw_parse()?; + let coins = helpers::parse_coins()?; + + let admin = Text::new("Admin addr") + .with_help_message("Press ESC to not set admin") + .prompt_skippable()? + .map(Addr::unchecked); + + if Self::confirm_action("Execute", &instantiate_msg, Some(coins.as_slice()))? { + let res = self.contract.instantiate( + &instantiate_msg, + admin.as_ref(), + Some(coins.as_slice()), + )?; + println!("Instantiation succesfull, hash: {}", res.txhash); + } Ok(()) } fn execute(&self) -> cw_orch::anyhow::Result<()> { - let execute_msg = ::ExecuteMsg::parse()?; - - // TODO: support attaching coins - self.contract.execute(&execute_msg, None)?; - + let execute_msg = ::ExecuteMsg::cw_parse()?; + let coins = helpers::parse_coins()?; + + if Self::confirm_action("Execute", &execute_msg, Some(coins.as_slice()))? { + let res = self + .contract + .execute(&execute_msg, Some(coins.as_slice()))?; + println!("Execution succesfull, hash: {}", res.txhash); + } Ok(()) } fn query(&self) -> cw_orch::anyhow::Result<()> { - let query_msg = ::QueryMsg::parse()?; + let query_msg = ::QueryMsg::cw_parse()?; let resp: serde_json::Value = self.contract.query(&query_msg)?; println!("{}", serde_json::to_string_pretty(&resp)?); @@ -94,15 +112,51 @@ where fn migrate(&self) -> cw_orch::anyhow::Result<()> { let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; - let migrate_msg = ::MigrateMsg::parse()?; - self.contract.migrate(&migrate_msg, new_code_id)?; + let migrate_msg = ::MigrateMsg::cw_parse()?; + + if Self::confirm_action("Migrate", &migrate_msg, None)? { + let res = self.contract.migrate(&migrate_msg, new_code_id)?; + println!("Migrate succesfull, hash: {}", res.txhash); + } Ok(()) } + + fn confirm_action( + action: &str, + message: T, + coins: Option<&[Coin]>, + ) -> cw_orch::anyhow::Result { + let mut message = format!( + "Confirm {action}, with message: {}", + serde_json::to_string(&message).unwrap() + ); + if let Some(c) = coins { + let coins_str = c.iter().map(|c| c.to_string()).collect::>(); + write!(message, ", and attached coins: {coins_str:?}",)?; + } + Ok(Confirm::new(&message).prompt_skippable()? == Some(true)) + } } pub mod helpers { use super::*; + pub fn parse_coins() -> cw_orch::anyhow::Result> { + let mut coins = Vec::new(); + loop { + let coin = CustomType::::new("Add coin to transaction") + .with_placeholder("5ucosm") + .with_help_message("Press ESC to finish adding coins") + .prompt_skippable()?; + if let Some(c) = coin { + coins.push(c) + } else { + break; + } + } + Ok(coins) + } + pub fn custom_type_serialize( message: &str, ) -> cw_orch::anyhow::Result { From 16c25529fc845cfd9511b24abb84a89853a0b542 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 14 Aug 2023 18:47:57 +0300 Subject: [PATCH 012/135] fix generics as variants --- packages/cw-orch-cli-derive/src/lib.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index 91f5a5347..876f52327 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -42,17 +42,23 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { let variants_as_structs = data.variants.iter().map(|variant| { let struct_name = &variant.ident; - let fields = &variant.fields; + let syn::Fields::Named(FieldsNamed { + named, + .. + }) = &variant.fields else { + unimplemented!() + }; + let field_names = named.into_iter().map(|a| a.ident.clone().unwrap()); + let field_names = quote!({#(#field_names),*}); let into_enum = quote!( impl From<#struct_name> for #name { fn from(val: #struct_name) -> Self { - let #struct_name #fields = val; - #name::#struct_name - #fields - + let #struct_name #field_names = val; + #name::#struct_name #field_names } } ); + let fields = &variant.fields; let sub_derived_trait_impl = impl_parse_for_struct(fields, struct_name); quote!( struct #struct_name From d07426fcef332b94d282b906db41007493488c5b Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 15 Aug 2023 15:15:50 +0300 Subject: [PATCH 013/135] add state_interface to cw_parse Helps to read daemon state inside cw_parse --- packages/cw-orch-cli-derive/src/lib.rs | 6 ++-- packages/cw-orch-cli/src/contract/mod.rs | 44 +++++++++++++++--------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index 876f52327..eb6646a56 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -70,14 +70,14 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse() -> ::cw_orch::anyhow::Result { + fn cw_parse(state_interface: &::std::rc::Rc<::cw_orch::daemon::DaemonState>) -> ::cw_orch::anyhow::Result { #enum_of_variant_names #display_for_enum_variant_names let options = vec![#(#enum_variants_ident::#idents),*]; let variant = ::cw_orch_cli::select_msg(options)?; #(#variants_as_structs)* let msg = match variant { - #(#enum_variants_ident::#idents => #idents::cw_parse()?.into()),* + #(#enum_variants_ident::#idents => #idents::cw_parse(state_interface)?.into()),* }; Ok(msg) } @@ -107,7 +107,7 @@ fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_mac let derived_trait_impl = quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse() -> ::cw_orch::anyhow::Result { + fn cw_parse(_state_interface: &::std::rc::Rc<::cw_orch::daemon::DaemonState>) -> ::cw_orch::anyhow::Result { Ok(Self { #(#fields),* }) diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index 90f622c13..d356845a3 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -1,9 +1,17 @@ -use std::fmt::{Display, Write}; +use std::{ + fmt::{Display, Write}, + rc::Rc, +}; use cosmwasm_std::{Addr, Coin}; -use cw_orch::prelude::{ - ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, - Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, +use cw_orch::{ + daemon::DaemonState, + prelude::{ + ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, + CwOrchUpload, Daemon, ExecutableContract, InstantiableContract, MigratableContract, + QueryableContract, + }, + state::ChainState, }; use inquire::{ui::RenderConfig, Confirm, CustomType, Text}; @@ -34,7 +42,7 @@ pub trait ParseCwMsg where Self: Sized, { - fn cw_parse() -> cw_orch::anyhow::Result; + fn cw_parse(state: &Rc) -> cw_orch::anyhow::Result; } impl ContractCli @@ -52,25 +60,27 @@ where { pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { let instance = ContractCli { contract }; + let state_interface = instance.contract.get_chain().state(); loop { let action = inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; match action { - ActionVariants::Execute => instance.execute()?, - ActionVariants::Query => instance.query()?, + ActionVariants::Execute => instance.execute(&state_interface)?, + ActionVariants::Query => instance.query(&state_interface)?, ActionVariants::Deploy => { instance.contract.upload()?; println!("Code_id: {}", instance.contract.addr_str()?); } - ActionVariants::Instantiate => instance.instantiate()?, - ActionVariants::Migrate => instance.migrate()?, + ActionVariants::Instantiate => instance.instantiate(&state_interface)?, + ActionVariants::Migrate => instance.migrate(&state_interface)?, ActionVariants::Quit => return Ok(()), } } } - fn instantiate(&self) -> cw_orch::anyhow::Result<()> { - let instantiate_msg = ::InstantiateMsg::cw_parse()?; + fn instantiate(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { + let instantiate_msg = + ::InstantiateMsg::cw_parse(state_interface)?; let coins = helpers::parse_coins()?; let admin = Text::new("Admin addr") @@ -89,8 +99,8 @@ where Ok(()) } - fn execute(&self) -> cw_orch::anyhow::Result<()> { - let execute_msg = ::ExecuteMsg::cw_parse()?; + fn execute(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { + let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; let coins = helpers::parse_coins()?; if Self::confirm_action("Execute", &execute_msg, Some(coins.as_slice()))? { @@ -102,17 +112,17 @@ where Ok(()) } - fn query(&self) -> cw_orch::anyhow::Result<()> { - let query_msg = ::QueryMsg::cw_parse()?; + fn query(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { + let query_msg = ::QueryMsg::cw_parse(state_interface)?; let resp: serde_json::Value = self.contract.query(&query_msg)?; println!("{}", serde_json::to_string_pretty(&resp)?); Ok(()) } - fn migrate(&self) -> cw_orch::anyhow::Result<()> { + fn migrate(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; - let migrate_msg = ::MigrateMsg::cw_parse()?; + let migrate_msg = ::MigrateMsg::cw_parse(state_interface)?; if Self::confirm_action("Migrate", &migrate_msg, None)? { let res = self.contract.migrate(&migrate_msg, new_code_id)?; From 6093b1b241cdf8b2848a7674e61ffa36e1348486 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 15 Aug 2023 15:41:13 +0300 Subject: [PATCH 014/135] StateInterface is enough --- packages/cw-orch-cli-derive/src/lib.rs | 4 ++-- packages/cw-orch-cli/src/contract/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index eb6646a56..aec823e62 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -70,7 +70,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse(state_interface: &::std::rc::Rc<::cw_orch::daemon::DaemonState>) -> ::cw_orch::anyhow::Result { + fn cw_parse(state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch::anyhow::Result { #enum_of_variant_names #display_for_enum_variant_names let options = vec![#(#enum_variants_ident::#idents),*]; @@ -107,7 +107,7 @@ fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_mac let derived_trait_impl = quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse(_state_interface: &::std::rc::Rc<::cw_orch::daemon::DaemonState>) -> ::cw_orch::anyhow::Result { + fn cw_parse(_state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch::anyhow::Result { Ok(Self { #(#fields),* }) diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index d356845a3..66bdd97bc 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -42,7 +42,7 @@ pub trait ParseCwMsg where Self: Sized, { - fn cw_parse(state: &Rc) -> cw_orch::anyhow::Result; + fn cw_parse(state: &impl cw_orch::state::StateInterface) -> cw_orch::anyhow::Result; } impl ContractCli From 682ecfeedb5e3905111707acedefd97e2fb1b18f Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 15 Aug 2023 16:28:48 +0300 Subject: [PATCH 015/135] parse into Empty --- packages/cw-orch-cli/src/contract/mod.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index 66bdd97bc..d1fad261c 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -3,7 +3,7 @@ use std::{ rc::Rc, }; -use cosmwasm_std::{Addr, Coin}; +use cosmwasm_std::{Addr, Coin, Empty}; use cw_orch::{ daemon::DaemonState, prelude::{ @@ -22,10 +22,11 @@ use strum::{Display, EnumIter, IntoEnumIterator}; enum ActionVariants { Execute, Query, - Deploy, + Upload, Instantiate, Migrate, Quit, + // TODO: Addons } pub struct ContractCli< @@ -45,6 +46,12 @@ where fn cw_parse(state: &impl cw_orch::state::StateInterface) -> cw_orch::anyhow::Result; } +impl ParseCwMsg for Empty { + fn cw_parse(_state: &impl cw_orch::state::StateInterface) -> cw_orch::anyhow::Result { + Ok(Empty {}) + } +} + impl ContractCli where Contract: ContractInstance @@ -67,7 +74,7 @@ where match action { ActionVariants::Execute => instance.execute(&state_interface)?, ActionVariants::Query => instance.query(&state_interface)?, - ActionVariants::Deploy => { + ActionVariants::Upload => { instance.contract.upload()?; println!("Code_id: {}", instance.contract.addr_str()?); } From 10d5681c08b564dd3e6a9a915fdf1eef8d0860d8 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 15 Aug 2023 20:09:25 +0300 Subject: [PATCH 016/135] sloppy addons implementation --- contracts/counter/examples/cli.rs | 7 ++++--- contracts/counter/src/contract.rs | 11 ++++++++++- packages/cw-orch-cli/Cargo.toml | 2 ++ packages/cw-orch-cli/src/lib.rs | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index 681815a64..5e70ac7b1 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -1,10 +1,11 @@ +use cosmwasm_std::Empty; use counter_contract::CounterContract; use cw_orch::{ anyhow, - prelude::{networks, DaemonBuilder}, + prelude::{networks, DaemonBuilder, Daemon}, tokio::runtime::Runtime, }; -use cw_orch_cli::ContractCli; +use cw_orch_cli::{ContractCli, CwCliAddons}; pub fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); @@ -18,7 +19,7 @@ pub fn main() -> anyhow::Result<()> { let counter = CounterContract::new("counter_contract", chain); - ContractCli::select_action(counter)?; + ContractCli::select_action(counter, Empty {})?; Ok(()) } diff --git a/contracts/counter/src/contract.rs b/contracts/counter/src/contract.rs index bac7e574d..c07a69c7b 100644 --- a/contracts/counter/src/contract.rs +++ b/contracts/counter/src/contract.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, + entry_point, to_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, }; use cw2::set_contract_version; @@ -9,6 +9,15 @@ use crate::{error::*, execute, msg::*, query, state::*}; pub const CONTRACT_NAME: &str = "crates.io:counter"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); +impl cw_orch_cli::CwCliAddons for CounterContract { + fn addons(&mut self, context: Empty) -> cw_orch::anyhow::Result<()> + where + Self: cw_orch::prelude::ContractInstance, + { + Ok(()) + } +} + // ANCHOR: interface_entry // ANCHOR: entry_point_line #[cfg_attr(feature = "export", entry_point)] diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 0a5f87bbf..1ef951dab 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -19,6 +19,8 @@ color-eyre = { version = "0.6" } inquire = { version = "0.6" } strum = { version = "0.24", features = ["derive"] } +dotenv = { version = "0.15.0" } + serde_json = "1.0.79" serde = { workspace = true } log = "0.4.14" diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 850859587..87acf8d53 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -5,6 +5,8 @@ pub use cw_orch_cli_derive::ParseCwMsg; pub use contract::{ // Helpers used by derive macro helpers::{custom_type_serialize, select_msg}, + AddonsContext, ContractCli, + CwCliAddons, ParseCwMsg, }; From 272615caa51d4c2682423507818d5a06dc89bbcd Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 15 Aug 2023 20:09:56 +0300 Subject: [PATCH 017/135] fmt --- contracts/counter/examples/cli.rs | 2 +- contracts/counter/src/contract.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index 5e70ac7b1..7c6f5ab91 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -2,7 +2,7 @@ use cosmwasm_std::Empty; use counter_contract::CounterContract; use cw_orch::{ anyhow, - prelude::{networks, DaemonBuilder, Daemon}, + prelude::{networks, Daemon, DaemonBuilder}, tokio::runtime::Runtime, }; use cw_orch_cli::{ContractCli, CwCliAddons}; diff --git a/contracts/counter/src/contract.rs b/contracts/counter/src/contract.rs index c07a69c7b..bf2ea3cec 100644 --- a/contracts/counter/src/contract.rs +++ b/contracts/counter/src/contract.rs @@ -10,7 +10,7 @@ pub const CONTRACT_NAME: &str = "crates.io:counter"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); impl cw_orch_cli::CwCliAddons for CounterContract { - fn addons(&mut self, context: Empty) -> cw_orch::anyhow::Result<()> + fn addons(&mut self, _context: Empty) -> cw_orch::anyhow::Result<()> where Self: cw_orch::prelude::ContractInstance, { From 202d0236327c7db2d08364945682fa7af9aa6ce0 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 16 Aug 2023 16:58:12 +0300 Subject: [PATCH 018/135] addons --- contracts/counter/examples/cli.rs | 4 +- contracts/counter/src/contract.rs | 11 +---- contracts/counter/src/lib.rs | 15 ++++++- packages/cw-orch-cli/src/contract/mod.rs | 51 ++++++++++++++++++++---- 4 files changed, 61 insertions(+), 20 deletions(-) diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index 7c6f5ab91..fdfea0cf7 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -2,10 +2,10 @@ use cosmwasm_std::Empty; use counter_contract::CounterContract; use cw_orch::{ anyhow, - prelude::{networks, Daemon, DaemonBuilder}, + prelude::{networks, DaemonBuilder}, tokio::runtime::Runtime, }; -use cw_orch_cli::{ContractCli, CwCliAddons}; +use cw_orch_cli::ContractCli; pub fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); diff --git a/contracts/counter/src/contract.rs b/contracts/counter/src/contract.rs index bf2ea3cec..bac7e574d 100644 --- a/contracts/counter/src/contract.rs +++ b/contracts/counter/src/contract.rs @@ -1,5 +1,5 @@ use cosmwasm_std::{ - entry_point, to_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdResult, + entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult, }; use cw2::set_contract_version; @@ -9,15 +9,6 @@ use crate::{error::*, execute, msg::*, query, state::*}; pub const CONTRACT_NAME: &str = "crates.io:counter"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); -impl cw_orch_cli::CwCliAddons for CounterContract { - fn addons(&mut self, _context: Empty) -> cw_orch::anyhow::Result<()> - where - Self: cw_orch::prelude::ContractInstance, - { - Ok(()) - } -} - // ANCHOR: interface_entry // ANCHOR: entry_point_line #[cfg_attr(feature = "export", entry_point)] diff --git a/contracts/counter/src/lib.rs b/contracts/counter/src/lib.rs index a265793b6..ad1ee892c 100644 --- a/contracts/counter/src/lib.rs +++ b/contracts/counter/src/lib.rs @@ -17,5 +17,18 @@ pub use crate::msg::{ExecuteMsgFns as CounterExecuteMsgFns, QueryMsgFns as Count // ANCHOR: custom_interface #[cfg(feature = "interface")] -mod interface; +mod interface { + use cosmwasm_std::Empty; + + use crate::CounterContract; + + impl cw_orch_cli::CwCliAddons for CounterContract { + fn addons(&mut self, _context: Empty) -> cw_orch::anyhow::Result<()> + where + Self: cw_orch::prelude::ContractInstance, + { + Ok(()) + } + } +} // ANCHOR_END: custom_interface diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index d1fad261c..14100bf7e 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -1,5 +1,6 @@ use std::{ fmt::{Display, Write}, + marker::PhantomData, rc::Rc, }; @@ -26,7 +27,15 @@ enum ActionVariants { Instantiate, Migrate, Quit, - // TODO: Addons + Info, + Addons, +} + +#[derive(Debug)] +#[allow(dead_code)] +struct ContractInfo { + addr: Option, + code_id: Option, } pub struct ContractCli< @@ -35,8 +44,10 @@ pub struct ContractCli< + ExecutableContract + QueryableContract + MigratableContract, + AddonsContext, > { pub(crate) contract: Contract, + addons_context: PhantomData, } pub trait ParseCwMsg @@ -52,21 +63,36 @@ impl ParseCwMsg for Empty { } } -impl ContractCli +pub trait AddonsContext: Clone {} + +impl AddonsContext for Empty {} + +pub trait CwCliAddons { + fn addons(&mut self, context: AddonsContext) -> cw_orch::anyhow::Result<()> + where + Self: ContractInstance; +} + +impl ContractCli where + C: AddonsContext, Contract: ContractInstance + CwOrchUpload + InstantiableContract + ExecutableContract + QueryableContract - + MigratableContract, + + MigratableContract + + CwCliAddons, ::InstantiateMsg: ParseCwMsg, ::ExecuteMsg: ParseCwMsg, ::QueryMsg: ParseCwMsg, ::MigrateMsg: ParseCwMsg, { - pub fn select_action(contract: Contract) -> cw_orch::anyhow::Result<()> { - let instance = ContractCli { contract }; + pub fn select_action(contract: Contract, context: C) -> cw_orch::anyhow::Result<()> { + let mut instance = ContractCli { + contract, + addons_context: PhantomData, + }; let state_interface = instance.contract.get_chain().state(); loop { let action = @@ -81,6 +107,14 @@ where ActionVariants::Instantiate => instance.instantiate(&state_interface)?, ActionVariants::Migrate => instance.migrate(&state_interface)?, ActionVariants::Quit => return Ok(()), + ActionVariants::Info => { + let contract_info = ContractInfo { + addr: instance.contract.address().ok(), + code_id: instance.contract.code_id().ok(), + }; + println!("{contract_info:?}"); + } + ActionVariants::Addons => instance.contract.addons(context.clone())?, } } } @@ -149,9 +183,12 @@ where ); if let Some(c) = coins { let coins_str = c.iter().map(|c| c.to_string()).collect::>(); - write!(message, ", and attached coins: {coins_str:?}",)?; + write!(message, ", and attached coins: {coins_str:?} y/n?",)?; } - Ok(Confirm::new(&message).prompt_skippable()? == Some(true)) + Ok(Confirm::new(&message) + .with_default(true) + .prompt_skippable()? + == Some(true)) } } From 10a5b57e81de2da006c681bc0bd47313e1730762 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 16 Aug 2023 21:23:40 +0300 Subject: [PATCH 019/135] from_cli for daemon --- packages/cw-orch-cli/src/daemon/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/cw-orch-cli/src/daemon/mod.rs diff --git a/packages/cw-orch-cli/src/daemon/mod.rs b/packages/cw-orch-cli/src/daemon/mod.rs new file mode 100644 index 000000000..2f12886e7 --- /dev/null +++ b/packages/cw-orch-cli/src/daemon/mod.rs @@ -0,0 +1,20 @@ +use cw_orch::{ + prelude::{networks::parse_network, Daemon, DaemonBuilder}, + tokio::runtime::Handle, +}; + +pub trait DaemonFromCli { + fn from_cli(handle: &Handle) -> cw_orch::anyhow::Result { + let network_str = inquire::Text::new("Chain id") + .with_placeholder("uni-6") + .prompt()?; + let network = parse_network(&network_str); + let chain = DaemonBuilder::default() + .handle(handle) + .chain(network) + .build()?; + Ok(chain) + } +} + +impl DaemonFromCli for Daemon {} From f21770b2cb054023093c66181de342d21fc483e0 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 16 Aug 2023 21:24:09 +0300 Subject: [PATCH 020/135] clean unused dependencies --- contracts/counter/Cargo.toml | 2 -- cw-orch/Cargo.toml | 5 ----- 2 files changed, 7 deletions(-) diff --git a/contracts/counter/Cargo.toml b/contracts/counter/Cargo.toml index 5cc0c56d0..7070e88b7 100644 --- a/contracts/counter/Cargo.toml +++ b/contracts/counter/Cargo.toml @@ -25,8 +25,6 @@ serde = { workspace = true } serde_json = "1.0.79" cw-orch = { path = "../../cw-orch", optional = true } -strum = { version = "0.25", features = ["derive"] } - cw-orch-cli = { path = "../../packages/cw-orch-cli", optional = true } [dev-dependencies] diff --git a/cw-orch/Cargo.toml b/cw-orch/Cargo.toml index 961fe2ecd..4688396f0 100644 --- a/cw-orch/Cargo.toml +++ b/cw-orch/Cargo.toml @@ -66,11 +66,6 @@ osmosis-test-tube = ["dep:osmosis-test-tube"] # Default deps cw-orch-contract-derive = { path = "../packages/cw-orch-contract-derive", version = "0.13.3" } cw-orch-fns-derive = { path = "../packages/cw-orch-fns-derive", version = "0.13.3" } -interactive-clap = "0.2.4" -clap = { version = "4.0.18", features = ["derive"] } -color-eyre = { version = "0.6" } -inquire = { version = "0.6" } -strum = { version = "0.25", features = ["derive"] } cosmwasm-std = { workspace = true } cw-utils = { workspace = true } From e2d25dfab012f6bd4b39dde53415fef6b8bc08db Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 16 Aug 2023 21:25:34 +0300 Subject: [PATCH 021/135] move to trait and create custom error --- contracts/counter/examples/cli.rs | 17 +- contracts/counter/src/lib.rs | 3 +- packages/cw-orch-cli-derive/src/lib.rs | 4 +- packages/cw-orch-cli/Cargo.toml | 1 + packages/cw-orch-cli/src/contract/error.rs | 15 ++ packages/cw-orch-cli/src/contract/mod.rs | 230 +++++++++++---------- packages/cw-orch-cli/src/lib.rs | 5 + 7 files changed, 151 insertions(+), 124 deletions(-) create mode 100644 packages/cw-orch-cli/src/contract/error.rs diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index fdfea0cf7..b174ac1ac 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -1,25 +1,16 @@ use cosmwasm_std::Empty; use counter_contract::CounterContract; -use cw_orch::{ - anyhow, - prelude::{networks, DaemonBuilder}, - tokio::runtime::Runtime, -}; -use cw_orch_cli::ContractCli; +use cw_orch::{anyhow, prelude::Daemon, tokio::runtime::Runtime}; +use cw_orch_cli::{ContractCli, DaemonFromCli}; pub fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); let rt = Runtime::new()?; - let network = networks::UNI_6; - let chain = DaemonBuilder::default() - .handle(rt.handle()) - .chain(network) - .build()?; - + let chain = Daemon::from_cli(rt.handle())?; let counter = CounterContract::new("counter_contract", chain); - ContractCli::select_action(counter, Empty {})?; + counter.select_action(Empty {})?; Ok(()) } diff --git a/contracts/counter/src/lib.rs b/contracts/counter/src/lib.rs index ad1ee892c..02c794152 100644 --- a/contracts/counter/src/lib.rs +++ b/contracts/counter/src/lib.rs @@ -19,11 +19,12 @@ pub use crate::msg::{ExecuteMsgFns as CounterExecuteMsgFns, QueryMsgFns as Count #[cfg(feature = "interface")] mod interface { use cosmwasm_std::Empty; + use cw_orch_cli::OrchCliResult; use crate::CounterContract; impl cw_orch_cli::CwCliAddons for CounterContract { - fn addons(&mut self, _context: Empty) -> cw_orch::anyhow::Result<()> + fn addons(&mut self, _context: Empty) -> OrchCliResult<()> where Self: cw_orch::prelude::ContractInstance, { diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index aec823e62..be93e3ad3 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -70,7 +70,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse(state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch::anyhow::Result { + fn cw_parse(state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_cli::OrchCliResult { #enum_of_variant_names #display_for_enum_variant_names let options = vec![#(#enum_variants_ident::#idents),*]; @@ -107,7 +107,7 @@ fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_mac let derived_trait_impl = quote!( #[automatically_derived] impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse(_state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch::anyhow::Result { + fn cw_parse(_state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_cli::OrchCliResult { Ok(Self { #(#fields),* }) diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 1ef951dab..0328de2bc 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -9,6 +9,7 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +thiserror = { version = "1.0.21" } # TODO: should be in workspace cosmwasm-std = { version = "1.3"} cw-orch = { path = "../../cw-orch", features = ["daemon"]} cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } diff --git a/packages/cw-orch-cli/src/contract/error.rs b/packages/cw-orch-cli/src/contract/error.rs new file mode 100644 index 000000000..829c0a753 --- /dev/null +++ b/packages/cw-orch-cli/src/contract/error.rs @@ -0,0 +1,15 @@ +use cw_orch::prelude::CwOrchError; +use inquire::error::InquireError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum OrchCliError { + #[error("{0}")] + InquireError(#[from] InquireError), + + #[error("{0}")] + CwOrchError(#[from] CwOrchError), + + #[error("Custom Error val: {val:?}")] + CustomError { val: String }, +} diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index 14100bf7e..bc8bd3f10 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -1,9 +1,12 @@ +mod error; + use std::{ fmt::{Display, Write}, - marker::PhantomData, rc::Rc, }; +pub type OrchCliResult = Result; + use cosmwasm_std::{Addr, Coin, Empty}; use cw_orch::{ daemon::DaemonState, @@ -15,10 +18,12 @@ use cw_orch::{ state::ChainState, }; -use inquire::{ui::RenderConfig, Confirm, CustomType, Text}; +use inquire::{error::InquireResult, ui::RenderConfig, Confirm, CustomType, InquireError, Text}; use serde::{de::DeserializeOwned, Serialize}; use strum::{Display, EnumIter, IntoEnumIterator}; +pub use self::error::OrchCliError; + #[derive(EnumIter, Display)] enum ActionVariants { Execute, @@ -26,102 +31,72 @@ enum ActionVariants { Upload, Instantiate, Migrate, - Quit, - Info, + ContractInfo, Addons, + Quit, } -#[derive(Debug)] +#[derive(Serialize)] #[allow(dead_code)] struct ContractInfo { addr: Option, code_id: Option, } -pub struct ContractCli< - Contract: ContractInstance - + InstantiableContract - + ExecutableContract - + QueryableContract - + MigratableContract, - AddonsContext, -> { - pub(crate) contract: Contract, - addons_context: PhantomData, -} - -pub trait ParseCwMsg -where - Self: Sized, -{ - fn cw_parse(state: &impl cw_orch::state::StateInterface) -> cw_orch::anyhow::Result; -} - -impl ParseCwMsg for Empty { - fn cw_parse(_state: &impl cw_orch::state::StateInterface) -> cw_orch::anyhow::Result { - Ok(Empty {}) - } -} - -pub trait AddonsContext: Clone {} - -impl AddonsContext for Empty {} - -pub trait CwCliAddons { - fn addons(&mut self, context: AddonsContext) -> cw_orch::anyhow::Result<()> - where - Self: ContractInstance; -} - -impl ContractCli +pub trait ContractCli where C: AddonsContext, - Contract: ContractInstance + Self: ContractInstance + CwOrchUpload + InstantiableContract + ExecutableContract + QueryableContract + MigratableContract + CwCliAddons, - ::InstantiateMsg: ParseCwMsg, - ::ExecuteMsg: ParseCwMsg, - ::QueryMsg: ParseCwMsg, - ::MigrateMsg: ParseCwMsg, + ::InstantiateMsg: ParseCwMsg, + ::ExecuteMsg: ParseCwMsg, + ::QueryMsg: ParseCwMsg, + ::MigrateMsg: ParseCwMsg, { - pub fn select_action(contract: Contract, context: C) -> cw_orch::anyhow::Result<()> { - let mut instance = ContractCli { - contract, - addons_context: PhantomData, - }; - let state_interface = instance.contract.get_chain().state(); + fn select_action(mut self, context: C) -> OrchCliResult<()> { + let state_interface = self.get_chain().state(); loop { let action = inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; - match action { - ActionVariants::Execute => instance.execute(&state_interface)?, - ActionVariants::Query => instance.query(&state_interface)?, + let res = match action { + ActionVariants::Execute => self.execute_cli(&state_interface), + ActionVariants::Query => self.query_cli(&state_interface), ActionVariants::Upload => { - instance.contract.upload()?; - println!("Code_id: {}", instance.contract.addr_str()?); + self.upload()?; + println!("Code_id: {}", self.code_id().unwrap()); + Ok(()) } - ActionVariants::Instantiate => instance.instantiate(&state_interface)?, - ActionVariants::Migrate => instance.migrate(&state_interface)?, - ActionVariants::Quit => return Ok(()), - ActionVariants::Info => { + ActionVariants::Instantiate => self.instantiate_cli(&state_interface), + ActionVariants::Migrate => self.migrate_cli(&state_interface), + ActionVariants::ContractInfo => { let contract_info = ContractInfo { - addr: instance.contract.address().ok(), - code_id: instance.contract.code_id().ok(), + addr: self.address().ok(), + code_id: self.code_id().ok(), }; - println!("{contract_info:?}"); + println!("{}", serde_json::to_string_pretty(&contract_info).unwrap()); + Ok(()) + } + ActionVariants::Addons => self.addons(context.clone()), + ActionVariants::Quit => return Ok(()), + }; + match res { + Err(OrchCliError::InquireError(InquireError::OperationCanceled)) | Ok(_) => {} + Err(err) => { + // Unrecoverable error? + return Err(err); } - ActionVariants::Addons => instance.contract.addons(context.clone())?, } } } - fn instantiate(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { + fn instantiate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let instantiate_msg = - ::InstantiateMsg::cw_parse(state_interface)?; + ::InstantiateMsg::cw_parse(state_interface)?; let coins = helpers::parse_coins()?; let admin = Text::new("Admin addr") @@ -129,73 +104,93 @@ where .prompt_skippable()? .map(Addr::unchecked); - if Self::confirm_action("Execute", &instantiate_msg, Some(coins.as_slice()))? { - let res = self.contract.instantiate( - &instantiate_msg, - admin.as_ref(), - Some(coins.as_slice()), - )?; - println!("Instantiation succesfull, hash: {}", res.txhash); + if helpers::confirm_action("Execute", &instantiate_msg, Some(coins.as_slice()))? { + let res = self.instantiate(&instantiate_msg, admin.as_ref(), Some(coins.as_slice()))?; + println!( + "Instantiation succesfull\naddr: {}\nhash: {}", + self.addr_str()?, + res.txhash + ); } Ok(()) } - fn execute(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { - let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; + fn execute_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { + let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; + // TODO: figure out a way to make this only with `payable` attribute let coins = helpers::parse_coins()?; - if Self::confirm_action("Execute", &execute_msg, Some(coins.as_slice()))? { - let res = self - .contract - .execute(&execute_msg, Some(coins.as_slice()))?; + if helpers::confirm_action("Execute", &execute_msg, Some(coins.as_slice()))? { + let res = self.execute(&execute_msg, Some(coins.as_slice()))?; println!("Execution succesfull, hash: {}", res.txhash); } Ok(()) } - fn query(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { - let query_msg = ::QueryMsg::cw_parse(state_interface)?; + fn query_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { + let query_msg = ::QueryMsg::cw_parse(state_interface)?; - let resp: serde_json::Value = self.contract.query(&query_msg)?; - println!("{}", serde_json::to_string_pretty(&resp)?); + let resp: serde_json::Value = self.query(&query_msg)?; + println!("{}", serde_json::to_string_pretty(&resp).unwrap()); Ok(()) } - fn migrate(&self, state_interface: &Rc) -> cw_orch::anyhow::Result<()> { + fn migrate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; - let migrate_msg = ::MigrateMsg::cw_parse(state_interface)?; + let migrate_msg = ::MigrateMsg::cw_parse(state_interface)?; - if Self::confirm_action("Migrate", &migrate_msg, None)? { - let res = self.contract.migrate(&migrate_msg, new_code_id)?; + if helpers::confirm_action("Migrate", &migrate_msg, None)? { + let res = self.migrate(&migrate_msg, new_code_id)?; println!("Migrate succesfull, hash: {}", res.txhash); } Ok(()) } +} - fn confirm_action( - action: &str, - message: T, - coins: Option<&[Coin]>, - ) -> cw_orch::anyhow::Result { - let mut message = format!( - "Confirm {action}, with message: {}", - serde_json::to_string(&message).unwrap() - ); - if let Some(c) = coins { - let coins_str = c.iter().map(|c| c.to_string()).collect::>(); - write!(message, ", and attached coins: {coins_str:?} y/n?",)?; - } - Ok(Confirm::new(&message) - .with_default(true) - .prompt_skippable()? - == Some(true)) +pub trait ParseCwMsg +where + Self: Sized, +{ + fn cw_parse(state: &impl cw_orch::state::StateInterface) -> OrchCliResult; +} + +impl ParseCwMsg for Empty { + fn cw_parse(_state: &impl cw_orch::state::StateInterface) -> OrchCliResult { + Ok(Empty {}) } } +pub trait AddonsContext: Clone {} + +impl AddonsContext for Empty {} + +pub trait CwCliAddons { + fn addons(&mut self, context: AddonsContext) -> OrchCliResult<()> + where + Self: ContractInstance; +} + +impl ContractCli for T +where + C: AddonsContext, + T: ContractInstance + + CwOrchUpload + + InstantiableContract + + ExecutableContract + + QueryableContract + + MigratableContract + + CwCliAddons, + ::InstantiateMsg: ParseCwMsg, + ::ExecuteMsg: ParseCwMsg, + ::QueryMsg: ParseCwMsg, + ::MigrateMsg: ParseCwMsg, +{ +} + pub mod helpers { use super::*; - pub fn parse_coins() -> cw_orch::anyhow::Result> { + pub fn parse_coins() -> InquireResult> { let mut coins = Vec::new(); loop { let coin = CustomType::::new("Add coin to transaction") @@ -213,7 +208,7 @@ pub mod helpers { pub fn custom_type_serialize( message: &str, - ) -> cw_orch::anyhow::Result { + ) -> InquireResult { let msg = CustomType { message, default: None, @@ -231,8 +226,27 @@ pub mod helpers { Ok(msg) } - pub fn select_msg(options: Vec) -> cw_orch::anyhow::Result { + pub fn select_msg(options: Vec) -> InquireResult { let variant = inquire::Select::new("Select Message", options).prompt()?; Ok(variant) } + + pub fn confirm_action( + action: &str, + message: T, + coins: Option<&[Coin]>, + ) -> InquireResult { + let mut message = format!( + "Confirm {action}, with message: {}", + serde_json::to_string(&message).unwrap() + ); + if let Some(c) = coins { + let coins_str = c.iter().map(|c| c.to_string()).collect::>(); + write!(message, ", and attached coins: {coins_str:?} y/n?",).unwrap(); + } + Ok(Confirm::new(&message) + .with_default(true) + .prompt_skippable()? + == Some(true)) + } } diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 87acf8d53..6fda2c56b 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,4 +1,7 @@ mod contract; +mod daemon; + +pub use daemon::DaemonFromCli; pub use cw_orch_cli_derive::ParseCwMsg; @@ -8,5 +11,7 @@ pub use contract::{ AddonsContext, ContractCli, CwCliAddons, + OrchCliError, + OrchCliResult, ParseCwMsg, }; From 2ea6567eb1abc14cbc1477c20c38521637304cb6 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 22 Aug 2023 19:04:18 +0300 Subject: [PATCH 022/135] main cli --- packages/cw-orch-cli/src/main.rs | 92 +++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index e7a11a969..ded6a96ff 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,3 +1,91 @@ -fn main() { - println!("Hello, world!"); +use cw_orch::{ + prelude::{networks::parse_network, Daemon, DaemonBuilder}, + tokio::runtime::{Handle, Runtime}, +}; + +use interactive_clap::{ResultFromCli, ToCliArgs}; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = Handle)] +#[interactive_clap(output_context = ChainDaemonContext)] +pub struct Commands { + chain_id: String, + #[interactive_clap(subcommand)] + action: CwAction, +} + +pub struct InitialContext<'a>(&'a Handle); + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = Daemon)] +pub enum CwAction { + /// Execute + #[strum_discriminants(strum(message = "Execute cosmwasm action"))] + Execute, + /// Query + #[strum_discriminants(strum(message = "Query cosmwasm action"))] + Query, +} + +pub struct ChainDaemonContext(Daemon); + +impl From for Daemon { + fn from(value: ChainDaemonContext) -> Self { + value.0 + } +} + +impl ChainDaemonContext { + fn from_previous_context( + _previous_context: Handle, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network(&scope.chain_id); + let daemon = DaemonBuilder::default() + .handle(&_previous_context) + .chain(chain) + .build()?; + Ok(ChainDaemonContext(daemon)) + } +} + +fn main() -> color_eyre::Result<()> { + dotenv::dotenv().ok(); + let mut cli_args = Commands::parse(); + let runtime = Runtime::new()?; + + loop { + let args = ::from_cli( + Some(cli_args), + runtime.handle().clone(), + ); + match args { + interactive_clap::ResultFromCli::Ok(cli_args) + | ResultFromCli::Cancel(Some(cli_args)) => { + println!( + "Your console command: {}", + shell_words::join(cli_args.to_cli_args()) + ); + return Ok(()); + } + interactive_clap::ResultFromCli::Cancel(None) => { + println!("Goodbye!"); + return Ok(()); + } + interactive_clap::ResultFromCli::Back => { + cli_args = Default::default(); + } + interactive_clap::ResultFromCli::Err(cli_args, err) => { + if let Some(cli_args) = cli_args { + println!( + "Your console command: {}", + shell_words::join(cli_args.to_cli_args()) + ); + } + return Err(err); + } + } + } } From 952da128c43f4165680de3cdb572b65ca3fa5516 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 22 Aug 2023 19:05:03 +0300 Subject: [PATCH 023/135] addonscontext autoimpl for clone --- packages/cw-orch-cli/src/contract/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index bc8bd3f10..7653eae10 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -160,9 +160,7 @@ impl ParseCwMsg for Empty { } } -pub trait AddonsContext: Clone {} - -impl AddonsContext for Empty {} +impl AddonsContext for T {} pub trait CwCliAddons { fn addons(&mut self, context: AddonsContext) -> OrchCliResult<()> From 8a53b5ddf4a333a1a02c4bba667be36a2411ec2e Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 4 Sep 2023 14:25:58 +0300 Subject: [PATCH 024/135] add key to keyring --- packages/cw-orch-cli/Cargo.toml | 14 +++- packages/cw-orch-cli/src/main.rs | 122 ++++++++++++++++++++++++++++--- 2 files changed, 121 insertions(+), 15 deletions(-) diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 0328de2bc..372d5a1c7 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -9,9 +9,15 @@ repository.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -thiserror = { version = "1.0.21" } # TODO: should be in workspace -cosmwasm-std = { version = "1.3"} -cw-orch = { path = "../../cw-orch", features = ["daemon"]} +thiserror = { workspace = true } +directories = "5.0.1" +keyring = "2.0.5" +rpassword = "7.2.0" +cosmrs = "0.14.0" +bip39 = { version = "2.0.0", features = ["rand"] } +base64 = { version = "0.21.0" } # TODO: move to workspace +cosmwasm-std = { version = "1.3" } +cw-orch = { path = "../../cw-orch", features = ["daemon"] } cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } interactive-clap = "0.2.4" interactive-clap-derive = "0.2.4" @@ -25,4 +31,4 @@ dotenv = { version = "0.15.0" } serde_json = "1.0.79" serde = { workspace = true } log = "0.4.14" -shell-words = "1.0.0" \ No newline at end of file +shell-words = "1.0.0" diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index ded6a96ff..f8f9c97df 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,3 +1,5 @@ +use base64::{engine::general_purpose::STANDARD as B64, Engine}; +use color_eyre::eyre::Context; use cw_orch::{ prelude::{networks::parse_network, Daemon, DaemonBuilder}, tokio::runtime::{Handle, Runtime}, @@ -9,13 +11,75 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = Handle)] #[interactive_clap(output_context = ChainDaemonContext)] -pub struct Commands { +pub struct TxCommands { chain_id: String, #[interactive_clap(subcommand)] action: CwAction, } -pub struct InitialContext<'a>(&'a Handle); +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(context = Handle)] +pub struct KeyCommands { + #[interactive_clap(subcommand)] + key_actions: KeyAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = Handle)] +pub enum KeyAction { + /// Add key to keyring + #[strum_discriminants(strum(message = "Add key to the keyring"))] + AddKey(AddKeyCommand), + /// Show key + #[strum_discriminants(strum(message = "Show key of given id from the keyring"))] + ShowKey, +} + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = Handle)] +#[interactive_clap(output_context = AddKeyContext)] +pub struct AddKeyCommand { + // TODO: add checker for repetition + // #[interactive_clap(skip_default_input_arg)] + name: String, + #[interactive_clap(subcommand)] + key_actions: AddKeyActions, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(input_context = AddKeyContext)] +#[interactive_clap(output_context = AddKeyOutput)] +pub enum AddKeyActions { + /// Generate new random key + #[strum_discriminants(strum(message = "Generate new random key"))] + New, + /// Recover key from the seed phrase + #[strum_discriminants(strum(message = "Recover key from the seed phrase"))] + FromSeed, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = Handle)] +///To construct a transaction you will need to provide information about sender (signer) and receiver accounts, and actions that needs to be performed. +///Do you want to derive some information required for transaction construction automatically querying it online? +pub enum Commands { + /// Create transaction + #[strum_discriminants(strum(message = "Create transaction"))] + Tx(TxCommands), + /// Key + #[strum_discriminants(strum(message = "Input key"))] + Key(KeyCommands), +} + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(context = Handle)] +pub struct TLCommand { + #[interactive_clap(subcommand)] + top_level: Commands, +} #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] @@ -29,6 +93,43 @@ pub enum CwAction { Query, } +#[derive(Clone)] +pub struct AddKeyContext(String); + +impl AddKeyContext { + fn from_previous_context( + _previous_context: Handle, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + Ok(AddKeyContext(scope.name.clone())) + } +} + +pub struct AddKeyOutput; + +impl AddKeyOutput { + fn from_previous_context( + previous_context: AddKeyContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let name = previous_context.0; + let mnemonic = match scope { + AddKeyActionsDiscriminants::New => bip39::Mnemonic::generate(24), + AddKeyActionsDiscriminants::FromSeed => { + let mnemonic_seed = + rpassword::prompt_password("Mnemonic 🔑: ").context("unable to read")?; + bip39::Mnemonic::parse_in(bip39::Language::English, mnemonic_seed) + } + }?; + let entry = keyring::Entry::new("cw-cli", &name)?; + + let entropy = mnemonic.to_entropy(); + let password = B64.encode(&entropy); + entry.set_password(&password)?; + Ok(AddKeyOutput) + } +} + pub struct ChainDaemonContext(Daemon); impl From for Daemon { @@ -39,12 +140,13 @@ impl From for Daemon { impl ChainDaemonContext { fn from_previous_context( - _previous_context: Handle, - scope:&::InteractiveClapContextScope, + previous_context: Handle, + scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { + // TODO: implement no-panic parse_network let chain = parse_network(&scope.chain_id); let daemon = DaemonBuilder::default() - .handle(&_previous_context) + .handle(&previous_context) .chain(chain) .build()?; Ok(ChainDaemonContext(daemon)) @@ -53,12 +155,12 @@ impl ChainDaemonContext { fn main() -> color_eyre::Result<()> { dotenv::dotenv().ok(); - let mut cli_args = Commands::parse(); + let cli_args = TLCommand::parse(); let runtime = Runtime::new()?; loop { - let args = ::from_cli( - Some(cli_args), + let args = ::from_cli( + Some(cli_args.clone()), runtime.handle().clone(), ); match args { @@ -74,9 +176,7 @@ fn main() -> color_eyre::Result<()> { println!("Goodbye!"); return Ok(()); } - interactive_clap::ResultFromCli::Back => { - cli_args = Default::default(); - } + interactive_clap::ResultFromCli::Back => {} interactive_clap::ResultFromCli::Err(cli_args, err) => { if let Some(cli_args) = cli_args { println!( From 4234d5f111b137bcee7c44ea00e146eb5b313cfe Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 15:37:09 +0300 Subject: [PATCH 025/135] refactor --- packages/cw-orch-cli/Cargo.toml | 2 +- .../src/commands/keys/add_key/mod.rs | 69 ++++++++ packages/cw-orch-cli/src/commands/keys/mod.rs | 26 +++ .../src/commands/keys/remove_key/mod.rs | 20 +++ .../src/commands/keys/show_key/mod.rs | 25 +++ packages/cw-orch-cli/src/commands/mod.rs | 16 ++ .../src/commands/transaction/mod.rs | 56 +++++++ packages/cw-orch-cli/src/main.rs | 157 +----------------- 8 files changed, 217 insertions(+), 154 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/keys/add_key/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/keys/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/keys/show_key/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/transaction/mod.rs diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 372d5a1c7..e8b4cd1a8 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -14,7 +14,7 @@ directories = "5.0.1" keyring = "2.0.5" rpassword = "7.2.0" cosmrs = "0.14.0" -bip39 = { version = "2.0.0", features = ["rand"] } +rand_core = { version = "0.6", features = ["std"] } base64 = { version = "0.21.0" } # TODO: move to workspace cosmwasm-std = { version = "1.3" } cw-orch = { path = "../../cw-orch", features = ["daemon"] } diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs new file mode 100644 index 000000000..42ca78e15 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -0,0 +1,69 @@ +use base64::{prelude::BASE64_STANDARD as B64, Engine}; +use color_eyre::eyre::Context; +use cosmrs::bip32; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = AddKeyContext)] +pub struct AddKeyCommand { + // TODO: add checker for repetition + // #[interactive_clap(skip_default_input_arg)] + /// Id of they key + name: String, + #[interactive_clap(subcommand)] + key_actions: AddKeyActions, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(input_context = AddKeyContext)] +#[interactive_clap(output_context = AddKeyOutput)] +/// How you want to create a new key? +pub enum AddKeyActions { + /// Generate new random key + #[strum_discriminants(strum(message = "Generate new random key"))] + New, + /// Recover key from the seed phrase + #[strum_discriminants(strum(message = "Recover key from the seed phrase"))] + FromSeed, +} + +#[derive(Clone)] +pub struct AddKeyContext(String); + +impl AddKeyContext { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + Ok(AddKeyContext(scope.name.clone())) + } +} + +pub struct AddKeyOutput; + +impl AddKeyOutput { + fn from_previous_context( + previous_context: AddKeyContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let name = previous_context.0; + let mnemonic = match scope { + AddKeyActionsDiscriminants::New => { + bip32::Mnemonic::random(&mut rand_core::OsRng, Default::default()) + } + AddKeyActionsDiscriminants::FromSeed => { + // TODO: do we want to hide the input? + let mnemonic_seed = + rpassword::prompt_password("Mnemonic 🔑: ").context("unable to read")?; + bip32::Mnemonic::new(mnemonic_seed, Default::default())? + } + }; + let entry = keyring::Entry::new("cw-cli", &name)?; + + let password = B64.encode(mnemonic.phrase().as_bytes()); + entry.set_password(&password)?; + Ok(AddKeyOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/keys/mod.rs b/packages/cw-orch-cli/src/commands/keys/mod.rs new file mode 100644 index 000000000..e48f10cd2 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/keys/mod.rs @@ -0,0 +1,26 @@ +mod add_key; +mod remove_key; +mod show_key; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +pub struct KeyCommands { + #[interactive_clap(subcommand)] + key_actions: KeyAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +/// Select key action +pub enum KeyAction { + /// Add key to the keyring + #[strum_discriminants(strum(message = "Add key to the keyring"))] + AddKey(add_key::AddKeyCommand), + /// Show key from keyring + #[strum_discriminants(strum(message = "Show key of given id from the keyring"))] + ShowKey(show_key::ShowKeyCommand), + /// Remove key from the keyring + #[strum_discriminants(strum(message = "Remove key from the keyring"))] + RemoveKey(remove_key::RemoveKeyCommand), +} diff --git a/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs new file mode 100644 index 000000000..62ea28def --- /dev/null +++ b/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs @@ -0,0 +1,20 @@ +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = RemoveKeyOutput)] +pub struct RemoveKeyCommand { + /// Id of the key + name: String, +} + +pub struct RemoveKeyOutput; + +impl RemoveKeyOutput { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let entry = keyring::Entry::new("cw-cli", &scope.name)?; + entry.delete_password()?; + Ok(RemoveKeyOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs new file mode 100644 index 000000000..860b1f403 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs @@ -0,0 +1,25 @@ +use base64::{prelude::BASE64_STANDARD as B64, Engine}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = ShowKeyOutput)] +pub struct ShowKeyCommand { + /// Id of the key + name: String, +} + +pub struct ShowKeyOutput; + +impl ShowKeyOutput { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let entry = keyring::Entry::new("cw-cli", &scope.name)?; + + let password = entry.get_password()?; + let phrase = String::from_utf8(B64.decode(password)?)?; + println!("phrase: {phrase}"); + Ok(ShowKeyOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs new file mode 100644 index 000000000..47294e749 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -0,0 +1,16 @@ +mod keys; +mod transaction; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +/// Select one of the options with up-down arrows and press enter to select action +pub enum Commands { + /// Construct transaction + #[strum_discriminants(strum(message = "Create transaction"))] + Tx(transaction::TxCommands), + /// Add, View or Remove key + #[strum_discriminants(strum(message = "Manage keys"))] + Key(keys::KeyCommands), +} diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs new file mode 100644 index 000000000..2bc56642b --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -0,0 +1,56 @@ +use cw_orch::{prelude::{DaemonAsync, networks::parse_network, DaemonAsyncBuilder}, tokio::{task, runtime::Handle}}; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = ChainDaemonContext)] +pub struct TxCommands { + chain_id: String, + #[interactive_clap(subcommand)] + action: CwAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = DaemonAsync)] +/// Select cosmwasm action +pub enum CwAction { + /// Execute + #[strum_discriminants(strum(message = "Execute cosmwasm message"))] + Execute, + /// Query + #[strum_discriminants(strum(message = "Query cosmwasm message"))] + Query, +} + +pub struct ChainDaemonContext(DaemonAsync); + +impl From for DaemonAsync { + fn from(value: ChainDaemonContext) -> Self { + value.0 + } +} + +impl ChainDaemonContext { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + // TODO: implement no-panic parse_network + let chain = parse_network(&scope.chain_id); + + let daemon = task::block_in_place(move || { + Handle::current().block_on(async move { + { + DaemonAsyncBuilder::default() + .chain(chain) + .build() + .await + .unwrap() + } + }) + }); + + Ok(ChainDaemonContext(daemon)) + } +} \ No newline at end of file diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index f8f9c97df..ebebe4110 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,168 +1,19 @@ -use base64::{engine::general_purpose::STANDARD as B64, Engine}; -use color_eyre::eyre::Context; -use cw_orch::{ - prelude::{networks::parse_network, Daemon, DaemonBuilder}, - tokio::runtime::{Handle, Runtime}, -}; +mod commands; use interactive_clap::{ResultFromCli, ToCliArgs}; -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = Handle)] -#[interactive_clap(output_context = ChainDaemonContext)] -pub struct TxCommands { - chain_id: String, - #[interactive_clap(subcommand)] - action: CwAction, -} - -#[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(context = Handle)] -pub struct KeyCommands { - #[interactive_clap(subcommand)] - key_actions: KeyAction, -} - -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = Handle)] -pub enum KeyAction { - /// Add key to keyring - #[strum_discriminants(strum(message = "Add key to the keyring"))] - AddKey(AddKeyCommand), - /// Show key - #[strum_discriminants(strum(message = "Show key of given id from the keyring"))] - ShowKey, -} - -#[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = Handle)] -#[interactive_clap(output_context = AddKeyContext)] -pub struct AddKeyCommand { - // TODO: add checker for repetition - // #[interactive_clap(skip_default_input_arg)] - name: String, - #[interactive_clap(subcommand)] - key_actions: AddKeyActions, -} - -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(input_context = AddKeyContext)] -#[interactive_clap(output_context = AddKeyOutput)] -pub enum AddKeyActions { - /// Generate new random key - #[strum_discriminants(strum(message = "Generate new random key"))] - New, - /// Recover key from the seed phrase - #[strum_discriminants(strum(message = "Recover key from the seed phrase"))] - FromSeed, -} - -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = Handle)] -///To construct a transaction you will need to provide information about sender (signer) and receiver accounts, and actions that needs to be performed. -///Do you want to derive some information required for transaction construction automatically querying it online? -pub enum Commands { - /// Create transaction - #[strum_discriminants(strum(message = "Create transaction"))] - Tx(TxCommands), - /// Key - #[strum_discriminants(strum(message = "Input key"))] - Key(KeyCommands), -} - -#[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(context = Handle)] pub struct TLCommand { #[interactive_clap(subcommand)] - top_level: Commands, -} - -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = Daemon)] -pub enum CwAction { - /// Execute - #[strum_discriminants(strum(message = "Execute cosmwasm action"))] - Execute, - /// Query - #[strum_discriminants(strum(message = "Query cosmwasm action"))] - Query, -} - -#[derive(Clone)] -pub struct AddKeyContext(String); - -impl AddKeyContext { - fn from_previous_context( - _previous_context: Handle, - scope:&::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - Ok(AddKeyContext(scope.name.clone())) - } -} - -pub struct AddKeyOutput; - -impl AddKeyOutput { - fn from_previous_context( - previous_context: AddKeyContext, - scope:&::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - let name = previous_context.0; - let mnemonic = match scope { - AddKeyActionsDiscriminants::New => bip39::Mnemonic::generate(24), - AddKeyActionsDiscriminants::FromSeed => { - let mnemonic_seed = - rpassword::prompt_password("Mnemonic 🔑: ").context("unable to read")?; - bip39::Mnemonic::parse_in(bip39::Language::English, mnemonic_seed) - } - }?; - let entry = keyring::Entry::new("cw-cli", &name)?; - - let entropy = mnemonic.to_entropy(); - let password = B64.encode(&entropy); - entry.set_password(&password)?; - Ok(AddKeyOutput) - } -} - -pub struct ChainDaemonContext(Daemon); - -impl From for Daemon { - fn from(value: ChainDaemonContext) -> Self { - value.0 - } -} - -impl ChainDaemonContext { - fn from_previous_context( - previous_context: Handle, - scope:&::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - // TODO: implement no-panic parse_network - let chain = parse_network(&scope.chain_id); - let daemon = DaemonBuilder::default() - .handle(&previous_context) - .chain(chain) - .build()?; - Ok(ChainDaemonContext(daemon)) - } + top_level: commands::Commands, } fn main() -> color_eyre::Result<()> { - dotenv::dotenv().ok(); + // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); - let runtime = Runtime::new()?; loop { - let args = ::from_cli( - Some(cli_args.clone()), - runtime.handle().clone(), - ); + let args = ::from_cli(Some(cli_args.clone()), ()); match args { interactive_clap::ResultFromCli::Ok(cli_args) | ResultFromCli::Cancel(Some(cli_args)) => { From 024227ca67a1077ea21bd9f22ce98ad752ff0cc4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 16:49:24 +0300 Subject: [PATCH 026/135] clean ups --- packages/cw-orch-cli-derive/src/lib.rs | 5 +-- packages/cw-orch-cli/Cargo.toml | 1 - .../src/commands/keys/add_key/mod.rs | 16 +++++---- packages/cw-orch-cli/src/commands/keys/mod.rs | 6 ++-- .../src/commands/keys/remove_key/mod.rs | 4 ++- .../src/commands/keys/show_key/mod.rs | 4 ++- .../src/commands/transaction/mod.rs | 36 ------------------- packages/cw-orch-cli/src/main.rs | 11 +++--- packages/cw-orch-cli/src/utils.rs | 9 +++++ .../cw-orch-fns-derive/src/execute_fns.rs | 6 +--- 10 files changed, 37 insertions(+), 61 deletions(-) create mode 100644 packages/cw-orch-cli/src/utils.rs diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index be93e3ad3..b83e87937 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -92,10 +92,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { } fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_macro2::TokenStream { - let syn::Fields::Named(FieldsNamed { - named, - .. - }) = fields else { + let syn::Fields::Named(FieldsNamed { named, .. }) = fields else { unimplemented!() }; let fields = named.into_iter().map(|field| { diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index e8b4cd1a8..5f0bab511 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -12,7 +12,6 @@ repository.workspace = true thiserror = { workspace = true } directories = "5.0.1" keyring = "2.0.5" -rpassword = "7.2.0" cosmrs = "0.14.0" rand_core = { version = "0.6", features = ["std"] } base64 = { version = "0.21.0" } # TODO: move to workspace diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs index 42ca78e15..802bdc063 100644 --- a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -1,8 +1,9 @@ use base64::{prelude::BASE64_STANDARD as B64, Engine}; -use color_eyre::eyre::Context; use cosmrs::bip32; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; +use crate::utils::entry_for_seed; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = AddKeyContext)] @@ -51,17 +52,20 @@ impl AddKeyOutput { let name = previous_context.0; let mnemonic = match scope { AddKeyActionsDiscriminants::New => { - bip32::Mnemonic::random(&mut rand_core::OsRng, Default::default()) + bip32::Mnemonic::random(rand_core::OsRng, Default::default()) } AddKeyActionsDiscriminants::FromSeed => { // TODO: do we want to hide the input? - let mnemonic_seed = - rpassword::prompt_password("Mnemonic 🔑: ").context("unable to read")?; + let mnemonic_seed = inquire::Password::new("Mnemonic 🔑: ") + .with_display_mode(inquire::PasswordDisplayMode::Masked) + .with_display_toggle_enabled() + .prompt()?; bip32::Mnemonic::new(mnemonic_seed, Default::default())? } }; - let entry = keyring::Entry::new("cw-cli", &name)?; - + // TODO: do we want to output seed + // println!("seed: {}", mnemonic.phrase()); + let entry = entry_for_seed(&name)?; let password = B64.encode(mnemonic.phrase().as_bytes()); entry.set_password(&password)?; Ok(AddKeyOutput) diff --git a/packages/cw-orch-cli/src/commands/keys/mod.rs b/packages/cw-orch-cli/src/commands/keys/mod.rs index e48f10cd2..beda9a534 100644 --- a/packages/cw-orch-cli/src/commands/keys/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/mod.rs @@ -16,11 +16,11 @@ pub struct KeyCommands { pub enum KeyAction { /// Add key to the keyring #[strum_discriminants(strum(message = "Add key to the keyring"))] - AddKey(add_key::AddKeyCommand), + Add(add_key::AddKeyCommand), /// Show key from keyring #[strum_discriminants(strum(message = "Show key of given id from the keyring"))] - ShowKey(show_key::ShowKeyCommand), + Show(show_key::ShowKeyCommand), /// Remove key from the keyring #[strum_discriminants(strum(message = "Remove key from the keyring"))] - RemoveKey(remove_key::RemoveKeyCommand), + Remove(remove_key::RemoveKeyCommand), } diff --git a/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs index 62ea28def..335ef3ef6 100644 --- a/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs @@ -1,3 +1,5 @@ +use crate::utils::entry_for_seed; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = RemoveKeyOutput)] @@ -13,7 +15,7 @@ impl RemoveKeyOutput { _previous_context: (), scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let entry = keyring::Entry::new("cw-cli", &scope.name)?; + let entry = entry_for_seed(&scope.name)?; entry.delete_password()?; Ok(RemoveKeyOutput) } diff --git a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs index 860b1f403..4a03cfb08 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs @@ -1,5 +1,7 @@ use base64::{prelude::BASE64_STANDARD as B64, Engine}; +use crate::utils::entry_for_seed; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = ShowKeyOutput)] @@ -15,7 +17,7 @@ impl ShowKeyOutput { _previous_context: (), scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let entry = keyring::Entry::new("cw-cli", &scope.name)?; + let entry = entry_for_seed(&scope.name)?; let password = entry.get_password()?; let phrase = String::from_utf8(B64.decode(password)?)?; diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs index 2bc56642b..663cd5a94 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -1,9 +1,6 @@ -use cw_orch::{prelude::{DaemonAsync, networks::parse_network, DaemonAsyncBuilder}, tokio::{task, runtime::Handle}}; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = ())] -#[interactive_clap(output_context = ChainDaemonContext)] pub struct TxCommands { chain_id: String, #[interactive_clap(subcommand)] @@ -12,7 +9,6 @@ pub struct TxCommands { #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = DaemonAsync)] /// Select cosmwasm action pub enum CwAction { /// Execute @@ -22,35 +18,3 @@ pub enum CwAction { #[strum_discriminants(strum(message = "Query cosmwasm message"))] Query, } - -pub struct ChainDaemonContext(DaemonAsync); - -impl From for DaemonAsync { - fn from(value: ChainDaemonContext) -> Self { - value.0 - } -} - -impl ChainDaemonContext { - fn from_previous_context( - _previous_context: (), - scope:&::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - // TODO: implement no-panic parse_network - let chain = parse_network(&scope.chain_id); - - let daemon = task::block_in_place(move || { - Handle::current().block_on(async move { - { - DaemonAsyncBuilder::default() - .chain(chain) - .build() - .await - .unwrap() - } - }) - }); - - Ok(ChainDaemonContext(daemon)) - } -} \ No newline at end of file diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index ebebe4110..8bd9d268d 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,5 +1,5 @@ mod commands; - +mod utils; use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -12,14 +12,15 @@ fn main() -> color_eyre::Result<()> { // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); + let cw_cli_path = utils::get_cw_cli_exec_path(); loop { let args = ::from_cli(Some(cli_args.clone()), ()); match args { interactive_clap::ResultFromCli::Ok(cli_args) | ResultFromCli::Cancel(Some(cli_args)) => { println!( - "Your console command: {}", - shell_words::join(cli_args.to_cli_args()) + "Your console command: {}", + shell_words::join(std::iter::once(cw_cli_path).chain(cli_args.to_cli_args())) ); return Ok(()); } @@ -32,7 +33,9 @@ fn main() -> color_eyre::Result<()> { if let Some(cli_args) = cli_args { println!( "Your console command: {}", - shell_words::join(cli_args.to_cli_args()) + shell_words::join( + std::iter::once(cw_cli_path).chain(cli_args.to_cli_args()) + ) ); } return Err(err); diff --git a/packages/cw-orch-cli/src/utils.rs b/packages/cw-orch-cli/src/utils.rs new file mode 100644 index 000000000..c0b02e1e4 --- /dev/null +++ b/packages/cw-orch-cli/src/utils.rs @@ -0,0 +1,9 @@ +use keyring::Entry; + +pub fn entry_for_seed(name: &str) -> keyring::Result { + Entry::new_with_target("cw-orch", "cw-cli", name) +} + +pub fn get_cw_cli_exec_path() -> String { + std::env::args().next().unwrap() +} diff --git a/packages/cw-orch-fns-derive/src/execute_fns.rs b/packages/cw-orch-fns-derive/src/execute_fns.rs index 2eb24e783..1409453ed 100644 --- a/packages/cw-orch-fns-derive/src/execute_fns.rs +++ b/packages/cw-orch-fns-derive/src/execute_fns.rs @@ -23,11 +23,7 @@ pub fn execute_fns_derive(input: DeriveInput) -> TokenStream { let (maybe_into, entrypoint_msg_type, type_generics) = process_impl_into(&input.attrs, name, input.generics); - let syn::Data::Enum(syn::DataEnum { - variants, - .. - }) = input.data - else { + let syn::Data::Enum(syn::DataEnum { variants, .. }) = input.data else { unimplemented!(); }; From f480f40470ac965b74b3646b32433b8c438caa19 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 16:53:46 +0300 Subject: [PATCH 027/135] edit comment --- packages/cw-orch-cli/src/commands/transaction/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs index 663cd5a94..064bb9f0d 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -2,6 +2,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] pub struct TxCommands { + /// Chain id chain_id: String, #[interactive_clap(subcommand)] action: CwAction, From b071d899c9b54d40243cb3eb7826ef29d7eceea5 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 17:33:12 +0300 Subject: [PATCH 028/135] no need to confirm --- packages/cw-orch-cli/src/commands/keys/add_key/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs index 802bdc063..64d452782 100644 --- a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -59,11 +59,13 @@ impl AddKeyOutput { let mnemonic_seed = inquire::Password::new("Mnemonic 🔑: ") .with_display_mode(inquire::PasswordDisplayMode::Masked) .with_display_toggle_enabled() + .with_help_message("Show seed on ctrl+R") + .without_confirmation() .prompt()?; bip32::Mnemonic::new(mnemonic_seed, Default::default())? } }; - // TODO: do we want to output seed + // TODO: do we want to output seed? // println!("seed: {}", mnemonic.phrase()); let entry = entry_for_seed(&name)?; let password = B64.encode(mnemonic.phrase().as_bytes()); From a409558728f0906849721e02843d11fffd932bdc Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 17:34:35 +0300 Subject: [PATCH 029/135] messages fix --- packages/cw-orch-cli/src/commands/keys/add_key/mod.rs | 5 +---- packages/cw-orch-cli/src/commands/keys/show_key/mod.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs index 64d452782..ceb26c0f2 100644 --- a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -55,18 +55,15 @@ impl AddKeyOutput { bip32::Mnemonic::random(rand_core::OsRng, Default::default()) } AddKeyActionsDiscriminants::FromSeed => { - // TODO: do we want to hide the input? let mnemonic_seed = inquire::Password::new("Mnemonic 🔑: ") .with_display_mode(inquire::PasswordDisplayMode::Masked) .with_display_toggle_enabled() - .with_help_message("Show seed on ctrl+R") + .with_help_message("ctrl+R to unmask") .without_confirmation() .prompt()?; bip32::Mnemonic::new(mnemonic_seed, Default::default())? } }; - // TODO: do we want to output seed? - // println!("seed: {}", mnemonic.phrase()); let entry = entry_for_seed(&name)?; let password = B64.encode(mnemonic.phrase().as_bytes()); entry.set_password(&password)?; diff --git a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs index 4a03cfb08..49e84f3a1 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs @@ -21,7 +21,7 @@ impl ShowKeyOutput { let password = entry.get_password()?; let phrase = String::from_utf8(B64.decode(password)?)?; - println!("phrase: {phrase}"); + println!("your seed phrase: {phrase}"); Ok(ShowKeyOutput) } } From 0e4e41f0cece73af8e71ef6dc05bc31de2797f1b Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 17:51:14 +0300 Subject: [PATCH 030/135] format toml --- packages/cw-orch-cli-derive/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cw-orch-cli-derive/Cargo.toml b/packages/cw-orch-cli-derive/Cargo.toml index e6f5c1d75..47ffadb24 100644 --- a/packages/cw-orch-cli-derive/Cargo.toml +++ b/packages/cw-orch-cli-derive/Cargo.toml @@ -15,4 +15,4 @@ quote = "1" proc-macro2 = "1" syn = { version = "1", features = ["full", "extra-traits", "visit-mut"] } convert_case = "0.6.0" -interactive-clap = "0.2.4" \ No newline at end of file +interactive-clap = "0.2.4" From a4dac3f09d74ac22b9f2f7fb6d2d9c20644ec218 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 7 Sep 2023 22:28:38 +0300 Subject: [PATCH 031/135] cosmwasm execute --- .../src/commands/keys/add_key/mod.rs | 4 +- .../src/commands/keys/show_key/mod.rs | 9 +---- .../transaction/cosmwasm_tx/execute/mod.rs | 40 +++++++++++++++++++ .../commands/transaction/cosmwasm_tx/mod.rs | 23 +++++++++++ .../src/commands/transaction/mod.rs | 17 ++++---- packages/cw-orch-cli/src/contract/mod.rs | 20 +--------- packages/cw-orch-cli/src/lib.rs | 3 ++ packages/cw-orch-cli/src/utils.rs | 27 +++++++++++++ 8 files changed, 107 insertions(+), 36 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs index ceb26c0f2..a0d2ef21a 100644 --- a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -1,8 +1,8 @@ -use base64::{prelude::BASE64_STANDARD as B64, Engine}; +use base64::Engine; use cosmrs::bip32; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::utils::entry_for_seed; +use crate::utils::{entry_for_seed, B64}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] diff --git a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs index 49e84f3a1..cadca0607 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs @@ -1,6 +1,4 @@ -use base64::{prelude::BASE64_STANDARD as B64, Engine}; - -use crate::utils::entry_for_seed; +use crate::utils::seed_phrase_for_id; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] @@ -17,10 +15,7 @@ impl ShowKeyOutput { _previous_context: (), scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let entry = entry_for_seed(&scope.name)?; - - let password = entry.get_password()?; - let phrase = String::from_utf8(B64.decode(password)?)?; + let phrase = seed_phrase_for_id(&scope.name)?; println!("your seed phrase: {phrase}"); Ok(ShowKeyOutput) } diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs new file mode 100644 index 000000000..c10a97f96 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs @@ -0,0 +1,40 @@ +use cw_orch::prelude::{networks::parse_network, DaemonBuilder, TxHandler}; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = ExecuteWasmOutput)] +pub struct ExecuteCommands { + // TODO: verify it exists? + contract_address: String, + #[interactive_clap(subcommand)] + action: ExecuteAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = ExecuteWasmOutput)] +/// Select cosmwasm action +pub enum ExecuteAction { + /// Query + #[strum_discriminants(strum(message = "Query cosmwasm message"))] + Query, +} + +pub struct ExecuteWasmOutput; + +impl ExecuteWasmOutput { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network("uni-6"); + let seed = crate::utils::seed_phrase_for_id("aloha")?; + let coins = crate::utils::parse_coins()?; + + let d = DaemonBuilder::default().chain(chain).build()?; + d.execute(exec_msg, &coins, contract_address); + Ok(ExecuteWasmOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs new file mode 100644 index 000000000..90c529f2e --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs @@ -0,0 +1,23 @@ +mod execute; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +pub struct CwCommands { + /// Contract addr + contract_addr: String, + #[interactive_clap(subcommand)] + action: CwAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +/// Select cosmwasm action +pub enum CwAction { + /// Execute + #[strum_discriminants(strum(message = "Execute cosmwasm message"))] + Execute(execute::ExecuteCommands), + /// Query + #[strum_discriminants(strum(message = "Query cosmwasm message"))] + Query, +} diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs index 064bb9f0d..9aa3c83d4 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -1,3 +1,5 @@ +mod cosmwasm_tx; + use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -5,17 +7,14 @@ pub struct TxCommands { /// Chain id chain_id: String, #[interactive_clap(subcommand)] - action: CwAction, + action: TxAction, } #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] -/// Select cosmwasm action -pub enum CwAction { - /// Execute - #[strum_discriminants(strum(message = "Execute cosmwasm message"))] - Execute, - /// Query - #[strum_discriminants(strum(message = "Query cosmwasm message"))] - Query, +/// Select type of transaction +pub enum TxAction { + /// Cosmwasm Action + #[strum_discriminants(strum(message = "Execute cosmwasm action"))] + Cw(cosmwasm_tx::CwCommands), } diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index 83be09dd4..56619a5c4 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -97,7 +97,7 @@ where fn instantiate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let instantiate_msg = ::InstantiateMsg::cw_parse(state_interface)?; - let coins = helpers::parse_coins()?; + let coins = crate::utils::parse_coins()?; let admin = Text::new("Admin addr") .with_help_message("Press ESC to not set admin") @@ -118,7 +118,7 @@ where fn execute_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; // TODO: figure out a way to make this only with `payable` attribute - let coins = helpers::parse_coins()?; + let coins = crate::utils::parse_coins()?; if helpers::confirm_action("Execute", &execute_msg, Some(coins.as_slice()))? { let res = self.execute(&execute_msg, Some(coins.as_slice()))?; @@ -190,22 +190,6 @@ where pub mod helpers { use super::*; - pub fn parse_coins() -> InquireResult> { - let mut coins = Vec::new(); - loop { - let coin = CustomType::::new("Add coin to transaction") - .with_placeholder("5ucosm") - .with_help_message("Press ESC to finish adding coins") - .prompt_skippable()?; - if let Some(c) = coin { - coins.push(c) - } else { - break; - } - } - Ok(coins) - } - pub fn custom_type_serialize( message: &str, ) -> InquireResult { diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 6fda2c56b..c24303e5c 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,3 +1,6 @@ +/// Allow integrating keys and stuff +pub mod utils; + mod contract; mod daemon; diff --git a/packages/cw-orch-cli/src/utils.rs b/packages/cw-orch-cli/src/utils.rs index c0b02e1e4..e306ed6ba 100644 --- a/packages/cw-orch-cli/src/utils.rs +++ b/packages/cw-orch-cli/src/utils.rs @@ -1,9 +1,36 @@ +pub use base64::prelude::BASE64_STANDARD as B64; +use base64::Engine; +use cosmwasm_std::Coin; +use inquire::error::InquireResult; use keyring::Entry; pub fn entry_for_seed(name: &str) -> keyring::Result { Entry::new_with_target("cw-orch", "cw-cli", name) } +pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { + let entry = entry_for_seed(&name)?; + let password = entry.get_password()?; + let phrase = String::from_utf8(B64.decode(password)?)?; + Ok(phrase) +} + pub fn get_cw_cli_exec_path() -> String { std::env::args().next().unwrap() } + +pub fn parse_coins() -> InquireResult> { + let mut coins = Vec::new(); + loop { + let coin = inquire::CustomType::::new("Add coin to transaction") + .with_placeholder("5ucosm") + .with_help_message("Press ESC to finish adding coins") + .prompt_skippable()?; + if let Some(c) = coin { + coins.push(c) + } else { + break; + } + } + Ok(coins) +} From 1a6e378014f4d9ba244fda2fcd472248b1764140 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Sep 2023 14:29:45 +0300 Subject: [PATCH 032/135] execute wasm --- .../src/commands/keys/add_key/mod.rs | 2 +- .../src/commands/keys/remove_key/mod.rs | 2 +- .../src/commands/keys/show_key/mod.rs | 2 +- .../transaction/cosmwasm_tx/execute/mod.rs | 63 +++++++++++----- .../commands/transaction/cosmwasm_tx/mod.rs | 20 +++++ .../transaction/cosmwasm_tx/msg_type/mod.rs | 74 +++++++++++++++++++ packages/cw-orch-cli/src/common.rs | 60 +++++++++++++++ packages/cw-orch-cli/src/contract/mod.rs | 12 +-- packages/cw-orch-cli/src/lib.rs | 2 +- packages/cw-orch-cli/src/main.rs | 4 +- packages/cw-orch-cli/src/utils.rs | 36 --------- 11 files changed, 210 insertions(+), 67 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs create mode 100644 packages/cw-orch-cli/src/common.rs delete mode 100644 packages/cw-orch-cli/src/utils.rs diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs index a0d2ef21a..f4a9e138b 100644 --- a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -2,7 +2,7 @@ use base64::Engine; use cosmrs::bip32; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::utils::{entry_for_seed, B64}; +use crate::common::{entry_for_seed, B64}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] diff --git a/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs index 335ef3ef6..847e757a6 100644 --- a/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs @@ -1,4 +1,4 @@ -use crate::utils::entry_for_seed; +use crate::common::entry_for_seed; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] diff --git a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs index cadca0607..6764c8b7c 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs @@ -1,4 +1,4 @@ -use crate::utils::seed_phrase_for_id; +use crate::common::seed_phrase_for_id; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs index c10a97f96..f1490efde 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs @@ -1,40 +1,65 @@ +use color_eyre::eyre::Context; use cw_orch::prelude::{networks::parse_network, DaemonBuilder, TxHandler}; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; +use crate::common::CliCoins; + +use super::{msg_type, CwActionContext}; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = ())] +#[interactive_clap(input_context = CwActionContext)] #[interactive_clap(output_context = ExecuteWasmOutput)] pub struct ExecuteCommands { - // TODO: verify it exists? contract_address: String, - #[interactive_clap(subcommand)] - action: ExecuteAction, + #[interactive_clap(value_enum)] + #[interactive_clap(skip_default_input_arg)] + /// How do you want to pass the message arguments? + msg_type: msg_type::MsgType, + #[interactive_clap(skip_default_input_arg)] + /// Input coins + coins: CliCoins, + /// Signer + signer: String, } -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(input_context = ())] -#[interactive_clap(output_context = ExecuteWasmOutput)] -/// Select cosmwasm action -pub enum ExecuteAction { - /// Query - #[strum_discriminants(strum(message = "Query cosmwasm message"))] - Query, +impl ExecuteCommands { + fn input_msg_type( + _context: &CwActionContext, + ) -> color_eyre::eyre::Result> { + msg_type::input_msg_type() + } + + fn input_coins(_context: &CwActionContext) -> color_eyre::eyre::Result> { + crate::common::parse_coins() + .map(|c| Some(CliCoins(c))) + .wrap_err("Bad coins input") + } } +// #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +// #[strum_discriminants(derive(EnumMessage, EnumIter))] +// #[interactive_clap(input_context = ())] +// #[interactive_clap(output_context = ExecuteWasmOutput)] +// /// Select cosmwasm action +// pub enum ExecuteAction { +// /// Query +// #[strum_discriminants(strum(message = "Query cosmwasm message"))] +// Query, +// } + pub struct ExecuteWasmOutput; impl ExecuteWasmOutput { fn from_previous_context( - _previous_context: (), - scope:&::InteractiveClapContextScope, + previous_context: CwActionContext, + scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network("uni-6"); - let seed = crate::utils::seed_phrase_for_id("aloha")?; - let coins = crate::utils::parse_coins()?; + /// TODO: non-panic parse_network + let chain = parse_network(&previous_context.0); + let seed = crate::common::seed_phrase_for_id("aloha")?; + let coins = crate::common::parse_coins()?; let d = DaemonBuilder::default().chain(chain).build()?; - d.execute(exec_msg, &coins, contract_address); Ok(ExecuteWasmOutput) } } diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs index 90c529f2e..48c81b0ea 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs @@ -1,8 +1,11 @@ mod execute; +pub mod msg_type; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = CwActionContext)] pub struct CwCommands { /// Contract addr contract_addr: String, @@ -12,6 +15,7 @@ pub struct CwCommands { #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = CwActionContext)] /// Select cosmwasm action pub enum CwAction { /// Execute @@ -21,3 +25,19 @@ pub enum CwAction { #[strum_discriminants(strum(message = "Query cosmwasm message"))] Query, } + +#[derive(Clone)] +pub struct CwActionContext { + contract_addr: String, +} + +impl CwActionContext { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + Ok(CwActionContext { + contract_addr: scope.contract_addr.clone(), + }) + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs new file mode 100644 index 000000000..1dcc2ff26 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs @@ -0,0 +1,74 @@ +use std::str::FromStr; + +use base64::Engine; +use color_eyre::eyre::Context; +use inquire::Select; +use strum::{EnumDiscriminants, EnumIter, EnumMessage, IntoEnumIterator}; + +#[derive(Debug, EnumDiscriminants, Clone, clap::ValueEnum)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +/// How do you want to pass the message arguments? +pub enum MsgType { + #[strum_discriminants(strum(message = "json message"))] + /// Valid JSON string (e.g. {"foo": "bar"}) + JsonMsg, + #[strum_discriminants(strum(message = "base64 message"))] + /// Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==) + Base64Msg, +} + +impl interactive_clap::ToCli for MsgType { + type CliVariant = MsgType; +} + +impl std::str::FromStr for MsgType { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "json-msg" => Ok(Self::JsonMsg), + "base64-msg" => Ok(Self::Base64Msg), + _ => Err("MsgType: incorrect message type".to_string()), + } + } +} + +impl std::fmt::Display for MsgType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::JsonMsg => write!(f, "json-msg"), + Self::Base64Msg => write!(f, "base64-msg"), + } + } +} + +impl std::fmt::Display for MsgTypeDiscriminants { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::JsonMsg => write!(f, "json-msg"), + Self::Base64Msg => write!(f, "base64-msg"), + } + } +} + +pub fn input_msg_type() -> color_eyre::eyre::Result> { + let variants = MsgTypeDiscriminants::iter().collect::>(); + let selected = Select::new("How would you like to proceed?", variants).prompt()?; + match selected { + MsgTypeDiscriminants::JsonMsg => Ok(Some(MsgType::JsonMsg)), + MsgTypeDiscriminants::Base64Msg => Ok(Some(MsgType::Base64Msg)), + } +} + +pub fn msg_bytes( + args: String, + msg_type: MsgType, +) -> color_eyre::eyre::Result> { + match msg_type { + MsgType::JsonMsg => { + let data_json = + serde_json::Value::from_str(&args).wrap_err("Data not in JSON format!")?; + Ok(data_json.to_string().into_bytes()) + } + MsgType::Base64Msg => Ok(crate::common::B64.decode(&args)?), + } +} diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs new file mode 100644 index 000000000..b9f11b65d --- /dev/null +++ b/packages/cw-orch-cli/src/common.rs @@ -0,0 +1,60 @@ +pub use base64::prelude::BASE64_STANDARD as B64; +use base64::Engine; +use color_eyre::eyre::Context; +use inquire::{error::InquireResult, InquireError}; +use interactive_clap::ToCli; +use keyring::Entry; + +pub fn entry_for_seed(name: &str) -> keyring::Result { + Entry::new_with_target("cw-orch", "cw-cli", name) +} + +#[derive(Default, PartialEq, Eq, Debug, Clone)] +pub struct CliCoins(pub cosmwasm_std::Coins); + +impl std::fmt::Display for CliCoins { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl std::str::FromStr for CliCoins { + type Err = String; + fn from_str(s: &str) -> Result { + let coins = cosmwasm_std::Coins::from_str(s).map_err(|e| e.to_string())?; + Ok(CliCoins(coins)) + } +} + +impl ToCli for CliCoins { + type CliVariant = CliCoins; +} + +pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { + let entry = entry_for_seed(&name)?; + let password = entry.get_password()?; + let phrase = String::from_utf8(B64.decode(password)?)?; + Ok(phrase) +} + +pub fn get_cw_cli_exec_path() -> String { + std::env::args().next().unwrap() +} + +pub fn parse_coins() -> InquireResult { + let mut coins = cosmwasm_std::Coins::default(); + loop { + let coin = inquire::CustomType::::new("Add coin to transaction") + .with_placeholder("5ucosm") + .with_help_message("Press ESC to finish adding coins") + .prompt_skippable()?; + if let Some(c) = coin { + coins + .add(c) + .map_err(|e| InquireError::Custom(Box::new(e)))? + } else { + break; + } + } + Ok(coins) +} diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-cli/src/contract/mod.rs index 56619a5c4..58fab9109 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-cli/src/contract/mod.rs @@ -97,15 +97,15 @@ where fn instantiate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let instantiate_msg = ::InstantiateMsg::cw_parse(state_interface)?; - let coins = crate::utils::parse_coins()?; + let coins = crate::common::parse_coins()?; let admin = Text::new("Admin addr") .with_help_message("Press ESC to not set admin") .prompt_skippable()? .map(Addr::unchecked); - if helpers::confirm_action("Execute", &instantiate_msg, Some(coins.as_slice()))? { - let res = self.instantiate(&instantiate_msg, admin.as_ref(), Some(coins.as_slice()))?; + if helpers::confirm_action("Execute", &instantiate_msg, Some(&coins.to_vec()))? { + let res = self.instantiate(&instantiate_msg, admin.as_ref(), Some(&coins.to_vec()))?; println!( "Instantiation succesfull\naddr: {}\nhash: {}", self.addr_str()?, @@ -118,10 +118,10 @@ where fn execute_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; // TODO: figure out a way to make this only with `payable` attribute - let coins = crate::utils::parse_coins()?; + let coins = crate::common::parse_coins()?; - if helpers::confirm_action("Execute", &execute_msg, Some(coins.as_slice()))? { - let res = self.execute(&execute_msg, Some(coins.as_slice()))?; + if helpers::confirm_action("Execute", &execute_msg, Some(&coins.to_vec()))? { + let res = self.execute(&execute_msg, Some(&coins.to_vec()))?; println!("Execution succesfull, hash: {}", res.txhash); } Ok(()) diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index c24303e5c..bc401aa5b 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,5 +1,5 @@ /// Allow integrating keys and stuff -pub mod utils; +pub mod common; mod contract; mod daemon; diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index 8bd9d268d..b712ea933 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,5 +1,5 @@ mod commands; -mod utils; +mod common; use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -12,7 +12,7 @@ fn main() -> color_eyre::Result<()> { // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); - let cw_cli_path = utils::get_cw_cli_exec_path(); + let cw_cli_path = common::get_cw_cli_exec_path(); loop { let args = ::from_cli(Some(cli_args.clone()), ()); match args { diff --git a/packages/cw-orch-cli/src/utils.rs b/packages/cw-orch-cli/src/utils.rs deleted file mode 100644 index e306ed6ba..000000000 --- a/packages/cw-orch-cli/src/utils.rs +++ /dev/null @@ -1,36 +0,0 @@ -pub use base64::prelude::BASE64_STANDARD as B64; -use base64::Engine; -use cosmwasm_std::Coin; -use inquire::error::InquireResult; -use keyring::Entry; - -pub fn entry_for_seed(name: &str) -> keyring::Result { - Entry::new_with_target("cw-orch", "cw-cli", name) -} - -pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { - let entry = entry_for_seed(&name)?; - let password = entry.get_password()?; - let phrase = String::from_utf8(B64.decode(password)?)?; - Ok(phrase) -} - -pub fn get_cw_cli_exec_path() -> String { - std::env::args().next().unwrap() -} - -pub fn parse_coins() -> InquireResult> { - let mut coins = Vec::new(); - loop { - let coin = inquire::CustomType::::new("Add coin to transaction") - .with_placeholder("5ucosm") - .with_help_message("Press ESC to finish adding coins") - .prompt_skippable()?; - if let Some(c) = coin { - coins.push(c) - } else { - break; - } - } - Ok(coins) -} From 1c447b758fbe78ee23d37fde8ec79d372e59ca35 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Sep 2023 18:28:23 +0300 Subject: [PATCH 033/135] finished execute wasm --- .../transaction/cosmwasm_tx/execute/mod.rs | 51 +++++++++++-------- .../commands/transaction/cosmwasm_tx/mod.rs | 9 +++- .../transaction/cosmwasm_tx/msg_type/mod.rs | 6 +-- .../src/commands/transaction/mod.rs | 26 ++++++++++ packages/cw-orch-cli/src/common.rs | 17 +++++++ 5 files changed, 84 insertions(+), 25 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs index f1490efde..b03a9d7ac 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs @@ -1,6 +1,8 @@ use color_eyre::eyre::Context; -use cw_orch::prelude::{networks::parse_network, DaemonBuilder, TxHandler}; -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; +use cw_orch::{ + prelude::{networks::parse_network, DaemonAsync}, + tokio::runtime::Runtime, +}; use crate::common::CliCoins; @@ -15,10 +17,13 @@ pub struct ExecuteCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, + /// Enter message + msg: String, #[interactive_clap(skip_default_input_arg)] /// Input coins coins: CliCoins, - /// Signer + /// Signer id + // TODO: sign it from seed phrase signer: String, } @@ -35,18 +40,6 @@ impl ExecuteCommands { .wrap_err("Bad coins input") } } - -// #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -// #[strum_discriminants(derive(EnumMessage, EnumIter))] -// #[interactive_clap(input_context = ())] -// #[interactive_clap(output_context = ExecuteWasmOutput)] -// /// Select cosmwasm action -// pub enum ExecuteAction { -// /// Query -// #[strum_discriminants(strum(message = "Query cosmwasm message"))] -// Query, -// } - pub struct ExecuteWasmOutput; impl ExecuteWasmOutput { @@ -54,12 +47,30 @@ impl ExecuteWasmOutput { previous_context: CwActionContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - /// TODO: non-panic parse_network - let chain = parse_network(&previous_context.0); - let seed = crate::common::seed_phrase_for_id("aloha")?; - let coins = crate::common::parse_coins()?; + // TODO: non-panic parse_network + let chain = parse_network(&previous_context.chain_id); + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let coins = (&scope.coins).try_into()?; + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; + + let rt = Runtime::new()?; + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender.pub_addr()?, + contract: previous_context.contract_addr.parse()?, + msg, + funds: coins, + }; + daemon.sender.commit_tx(vec![exec_msg], None).await?; + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; - let d = DaemonBuilder::default().chain(chain).build()?; Ok(ExecuteWasmOutput) } } diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs index 48c81b0ea..c7c946618 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs @@ -1,10 +1,13 @@ mod execute; pub mod msg_type; +use cw_orch::daemon::ChainInfo; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; +use super::TxContext; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = ())] +#[interactive_clap(input_context = TxContext)] #[interactive_clap(output_context = CwActionContext)] pub struct CwCommands { /// Contract addr @@ -28,15 +31,17 @@ pub enum CwAction { #[derive(Clone)] pub struct CwActionContext { + chain_id: String, contract_addr: String, } impl CwActionContext { fn from_previous_context( - _previous_context: (), + previous_context: TxContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { Ok(CwActionContext { + chain_id: previous_context.chain_id.clone(), contract_addr: scope.contract_addr.clone(), }) } diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs index 1dcc2ff26..0440678ba 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs @@ -60,15 +60,15 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { } pub fn msg_bytes( - args: String, + message: String, msg_type: MsgType, ) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { let data_json = - serde_json::Value::from_str(&args).wrap_err("Data not in JSON format!")?; + serde_json::Value::from_str(&message).wrap_err("Data not in JSON format!")?; Ok(data_json.to_string().into_bytes()) } - MsgType::Base64Msg => Ok(crate::common::B64.decode(&args)?), + MsgType::Base64Msg => Ok(crate::common::B64.decode(&message)?), } } diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs index 9aa3c83d4..9b56675bf 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -1,8 +1,11 @@ mod cosmwasm_tx; +use cw_orch::{daemon::ChainInfo, prelude::networks::parse_network}; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = TxContext)] pub struct TxCommands { /// Chain id chain_id: String, @@ -12,9 +15,32 @@ pub struct TxCommands { #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = TxContext)] /// Select type of transaction pub enum TxAction { /// Cosmwasm Action #[strum_discriminants(strum(message = "Execute cosmwasm action"))] Cw(cosmwasm_tx::CwCommands), } + +impl From for () { + fn from(_value: TxContext) -> Self { + () + } +} + +#[derive(Clone)] +pub struct TxContext { + chain_id: String, +} + +impl TxContext { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + Ok(TxContext { + chain_id: scope.chain_id.clone(), + }) + } +} diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index b9f11b65d..8c7c9ed21 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -12,6 +12,23 @@ pub fn entry_for_seed(name: &str) -> keyring::Result { #[derive(Default, PartialEq, Eq, Debug, Clone)] pub struct CliCoins(pub cosmwasm_std::Coins); +impl TryFrom<&CliCoins> for Vec { + type Error = color_eyre::Report; + + fn try_from(value: &CliCoins) -> Result { + value + .0 + .iter() + .map(|cosmwasm_std::Coin { amount, denom }| { + Ok(cosmrs::Coin { + amount: amount.u128(), + denom: denom.parse()?, + }) + }) + .collect() + } +} + impl std::fmt::Display for CliCoins { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) From 6474a19dc309d9dd180cba4dbd8d7d43c8d8a1f3 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Sep 2023 19:06:14 +0300 Subject: [PATCH 034/135] query method --- packages/cw-orch-cli/src/commands/mod.rs | 2 +- .../transaction/cosmwasm_tx/execute/mod.rs | 6 +- .../commands/transaction/cosmwasm_tx/mod.rs | 10 +-- .../transaction/cosmwasm_tx/query/mod.rs | 64 +++++++++++++++++++ .../src/commands/transaction/mod.rs | 3 +- packages/cw-orch-cli/src/common.rs | 1 - 6 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index 47294e749..0fa69fc96 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -8,7 +8,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { /// Construct transaction - #[strum_discriminants(strum(message = "Create transaction"))] + #[strum_discriminants(strum(message = "Construct transaction"))] Tx(transaction::TxCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "Manage keys"))] diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs index b03a9d7ac..9a2d786f1 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs @@ -12,7 +12,6 @@ use super::{msg_type, CwActionContext}; #[interactive_clap(input_context = CwActionContext)] #[interactive_clap(output_context = ExecuteWasmOutput)] pub struct ExecuteCommands { - contract_address: String, #[interactive_clap(value_enum)] #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? @@ -23,7 +22,7 @@ pub struct ExecuteCommands { /// Input coins coins: CliCoins, /// Signer id - // TODO: sign it from seed phrase + // TODO: should be possible to sign it from the seed phrase signer: String, } @@ -67,7 +66,8 @@ impl ExecuteWasmOutput { msg, funds: coins, }; - daemon.sender.commit_tx(vec![exec_msg], None).await?; + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs index c7c946618..81863ab1c 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs @@ -1,7 +1,7 @@ mod execute; +mod query; pub mod msg_type; -use cw_orch::daemon::ChainInfo; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; use super::TxContext; @@ -10,7 +10,7 @@ use super::TxContext; #[interactive_clap(input_context = TxContext)] #[interactive_clap(output_context = CwActionContext)] pub struct CwCommands { - /// Contract addr + /// Contract address contract_addr: String, #[interactive_clap(subcommand)] action: CwAction, @@ -22,11 +22,11 @@ pub struct CwCommands { /// Select cosmwasm action pub enum CwAction { /// Execute - #[strum_discriminants(strum(message = "Execute cosmwasm message"))] + #[strum_discriminants(strum(message = "Execute"))] Execute(execute::ExecuteCommands), /// Query - #[strum_discriminants(strum(message = "Query cosmwasm message"))] - Query, + #[strum_discriminants(strum(message = "Query"))] + Query(query::QueryCommands), } #[derive(Clone)] diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs new file mode 100644 index 000000000..a6dfb547a --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs @@ -0,0 +1,64 @@ +use cosmrs::proto::cosmwasm::wasm::v1::{ + query_client::QueryClient, QuerySmartContractStateRequest, +}; +use cw_orch::{ + daemon::{ChainRegistryData, GrpcChannel}, + prelude::networks::parse_network, + tokio::runtime::Runtime, +}; + +use super::{msg_type, CwActionContext}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CwActionContext)] +#[interactive_clap(output_context = QueryWasmOutput)] +pub struct QueryCommands { + #[interactive_clap(value_enum)] + #[interactive_clap(skip_default_input_arg)] + /// How do you want to pass the message arguments? + msg_type: msg_type::MsgType, + /// Enter message + msg: String, +} + +impl QueryCommands { + fn input_msg_type( + _context: &CwActionContext, + ) -> color_eyre::eyre::Result> { + msg_type::input_msg_type() + } +} +pub struct QueryWasmOutput; + +impl QueryWasmOutput { + fn from_previous_context( + previous_context: CwActionContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + // TODO: non-panic parse_network + let chain = parse_network(&previous_context.chain_id); + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; + + let chain_data: ChainRegistryData = chain.into(); + + let rt = Runtime::new()?; + rt.block_on(async { + let grpc_channel = + GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + let mut client = QueryClient::new(grpc_channel); + + // TODO: support other types of queries + let resp = client + .smart_contract_state(QuerySmartContractStateRequest { + address: previous_context.contract_addr, + query_data: msg, + }) + .await?; + let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(QueryWasmOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs index 9b56675bf..128769a85 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -1,6 +1,5 @@ mod cosmwasm_tx; -use cw_orch::{daemon::ChainInfo, prelude::networks::parse_network}; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -19,7 +18,7 @@ pub struct TxCommands { /// Select type of transaction pub enum TxAction { /// Cosmwasm Action - #[strum_discriminants(strum(message = "Execute cosmwasm action"))] + #[strum_discriminants(strum(message = "Perform CosmWasm action"))] Cw(cosmwasm_tx::CwCommands), } diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 8c7c9ed21..23a30bcaf 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -1,6 +1,5 @@ pub use base64::prelude::BASE64_STANDARD as B64; use base64::Engine; -use color_eyre::eyre::Context; use inquire::{error::InquireResult, InquireError}; use interactive_clap::ToCli; use keyring::Entry; From 8646bb1365b34613996a5fe9658100826da450aa Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Sep 2023 19:09:30 +0300 Subject: [PATCH 035/135] fix comment --- packages/cw-orch-cli/src/commands/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index 0fa69fc96..e897711fd 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -7,8 +7,8 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[strum_discriminants(derive(EnumMessage, EnumIter))] /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { - /// Construct transaction - #[strum_discriminants(strum(message = "Construct transaction"))] + /// Construct action + #[strum_discriminants(strum(message = "Construct action"))] Tx(transaction::TxCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "Manage keys"))] From 0134cf61c0df581ea059b7c061f011959398d1d4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Sep 2023 18:40:54 +0300 Subject: [PATCH 036/135] instantiate and upload --- cw-orch-daemon/src/sender.rs | 4 +- packages/cw-orch-cli/Cargo.toml | 3 + packages/cw-orch-cli/src/commands/mod.rs | 2 +- .../commands/transaction/cosmwasm_tx/mod.rs | 50 ++++---- .../transaction/cosmwasm_tx/msg_type/mod.rs | 23 +++- .../transaction/cosmwasm_tx/query/mod.rs | 72 +++--------- .../query/query_contract_smart/mod.rs | 69 +++++++++++ .../cosmwasm_tx/{ => tx}/execute/mod.rs | 23 ++-- .../cosmwasm_tx/tx/instantiate/mod.rs | 110 ++++++++++++++++++ .../transaction/cosmwasm_tx/tx/mod.rs | 30 +++++ .../transaction/cosmwasm_tx/tx/store/mod.rs | 62 ++++++++++ .../src/commands/transaction/mod.rs | 24 ++-- packages/cw-orch-cli/src/common.rs | 41 +------ packages/cw-orch-cli/src/main.rs | 1 + packages/cw-orch-cli/src/types/coins.rs | 29 +++++ packages/cw-orch-cli/src/types/mod.rs | 7 ++ packages/cw-orch-cli/src/types/path_buf.rs | 21 ++++ packages/cw-orch-cli/src/types/skippable.rs | 33 ++++++ 18 files changed, 450 insertions(+), 154 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs rename packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/{ => tx}/execute/mod.rs (75%) create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs create mode 100644 packages/cw-orch-cli/src/types/coins.rs create mode 100644 packages/cw-orch-cli/src/types/mod.rs create mode 100644 packages/cw-orch-cli/src/types/path_buf.rs create mode 100644 packages/cw-orch-cli/src/types/skippable.rs diff --git a/cw-orch-daemon/src/sender.rs b/cw-orch-daemon/src/sender.rs index abd8504b3..12fb19f83 100644 --- a/cw-orch-daemon/src/sender.rs +++ b/cw-orch-daemon/src/sender.rs @@ -170,9 +170,7 @@ impl Sender { let suggested_fee = parse_suggested_fee(&tx_response.raw_log); let Some(new_fee) = suggested_fee else { - return Err(DaemonError::InsufficientFee( - tx_response.raw_log, - )); + return Err(DaemonError::InsufficientFee(tx_response.raw_log)); }; // update the fee and try again diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 5f0bab511..451577ef8 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -31,3 +31,6 @@ serde_json = "1.0.79" serde = { workspace = true } log = "0.4.14" shell-words = "1.0.0" + +tonic = "0.10.0" +derive_more = "0.99" \ No newline at end of file diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index e897711fd..bf1198eb0 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -9,7 +9,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; pub enum Commands { /// Construct action #[strum_discriminants(strum(message = "Construct action"))] - Tx(transaction::TxCommands), + Tx(transaction::CosmosCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "Manage keys"))] Key(keys::KeyCommands), diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs index 81863ab1c..a8d1beb45 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs @@ -1,48 +1,44 @@ -mod execute; -mod query; pub mod msg_type; +mod query; +mod tx; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use super::TxContext; +use super::CosmosContext; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = TxContext)] -#[interactive_clap(output_context = CwActionContext)] +#[interactive_clap(context = CosmosContext)] pub struct CwCommands { - /// Contract address - contract_addr: String, #[interactive_clap(subcommand)] action: CwAction, } #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = CwActionContext)] +#[interactive_clap(context = CosmosContext)] /// Select cosmwasm action pub enum CwAction { - /// Execute - #[strum_discriminants(strum(message = "Execute"))] - Execute(execute::ExecuteCommands), + /// Transaction + #[strum_discriminants(strum(message = "Transaction"))] + Tx(tx::TxCommands), /// Query #[strum_discriminants(strum(message = "Query"))] Query(query::QueryCommands), } -#[derive(Clone)] -pub struct CwActionContext { - chain_id: String, - contract_addr: String, -} +// TODO: remove if unused +// #[derive(Clone)] +// pub struct CwActionContext { +// chain_id: String, +// } -impl CwActionContext { - fn from_previous_context( - previous_context: TxContext, - scope:&::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - Ok(CwActionContext { - chain_id: previous_context.chain_id.clone(), - contract_addr: scope.contract_addr.clone(), - }) - } -} +// impl CwActionContext { +// fn from_previous_context( +// previous_context: TxContext, +// scope:&::InteractiveClapContextScope, +// ) -> color_eyre::eyre::Result { +// Ok(CwActionContext { +// chain_id: previous_context.chain_id.clone(), +// }) +// } +// } diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs index 0440678ba..6935eaad9 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs @@ -59,10 +59,7 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { } } -pub fn msg_bytes( - message: String, - msg_type: MsgType, -) -> color_eyre::eyre::Result> { +pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { let data_json = @@ -72,3 +69,21 @@ pub fn msg_bytes( MsgType::Base64Msg => Ok(crate::common::B64.decode(&message)?), } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn check_message() { + let b_64_msg = msg_bytes( + "eyJsYXRlc3RfY29udHJhY3RzIjp7fX0=".to_owned(), + MsgType::Base64Msg, + ) + .unwrap(); + let json_msg = + msg_bytes(r#"{"latest_contracts":{}}"#.to_owned(), MsgType::JsonMsg).unwrap(); + + assert_eq!(b_64_msg, json_msg); + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs index a6dfb547a..713fadc71 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs @@ -1,64 +1,22 @@ -use cosmrs::proto::cosmwasm::wasm::v1::{ - query_client::QueryClient, QuerySmartContractStateRequest, -}; -use cw_orch::{ - daemon::{ChainRegistryData, GrpcChannel}, - prelude::networks::parse_network, - tokio::runtime::Runtime, -}; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use super::{msg_type, CwActionContext}; +use crate::commands::transaction::CosmosContext; + +mod query_contract_smart; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = CwActionContext)] -#[interactive_clap(output_context = QueryWasmOutput)] +#[interactive_clap(context = CosmosContext)] pub struct QueryCommands { - #[interactive_clap(value_enum)] - #[interactive_clap(skip_default_input_arg)] - /// How do you want to pass the message arguments? - msg_type: msg_type::MsgType, - /// Enter message - msg: String, -} - -impl QueryCommands { - fn input_msg_type( - _context: &CwActionContext, - ) -> color_eyre::eyre::Result> { - msg_type::input_msg_type() - } + #[interactive_clap(subcommand)] + action: QueryAction, } -pub struct QueryWasmOutput; - -impl QueryWasmOutput { - fn from_previous_context( - previous_context: CwActionContext, - scope:&::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id); - let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; - - let chain_data: ChainRegistryData = chain.into(); - - let rt = Runtime::new()?; - rt.block_on(async { - let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; - let mut client = QueryClient::new(grpc_channel); - - // TODO: support other types of queries - let resp = client - .smart_contract_state(QuerySmartContractStateRequest { - address: previous_context.contract_addr, - query_data: msg, - }) - .await?; - let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); - color_eyre::Result::<(), color_eyre::Report>::Ok(()) - })?; - Ok(QueryWasmOutput) - } +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = CosmosContext)] +/// Select cosmwasm action +pub enum QueryAction { + /// Query wasm smart + #[strum_discriminants(strum(message = "Query wasm smart"))] + Query(query_contract_smart::QuerySmartCommands), } diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs new file mode 100644 index 000000000..ead73ce53 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs @@ -0,0 +1,69 @@ +use cosmrs::proto::cosmwasm::wasm::v1::{ + query_client::QueryClient, QuerySmartContractStateRequest, +}; +use cw_orch::{ + daemon::{ChainRegistryData, GrpcChannel}, + prelude::networks::parse_network, + tokio::runtime::Runtime, +}; + +use crate::commands::transaction::CosmosContext; + +use super::super::msg_type; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = QueryWasmOutput)] +pub struct QuerySmartCommands { + /// Contract address + contract_addr: String, + #[interactive_clap(value_enum)] + #[interactive_clap(skip_default_input_arg)] + /// How do you want to pass the message arguments? + msg_type: msg_type::MsgType, + /// Enter message + msg: String, +} + +impl QuerySmartCommands { + fn input_msg_type( + _context: &CosmosContext, + ) -> color_eyre::eyre::Result> { + msg_type::input_msg_type() + } +} +pub struct QueryWasmOutput; + +impl QueryWasmOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + // TODO: non-panic parse_network + let chain = parse_network(&previous_context.chain_id); + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; + + let chain_data: ChainRegistryData = chain.into(); + + let rt = Runtime::new()?; + rt.block_on(async { + let grpc_channel = + GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + let mut client = QueryClient::new(grpc_channel); + + // TODO: support other types of queries + // It should be possible to support `Any` on query + let resp = client + .smart_contract_state(QuerySmartContractStateRequest { + address: scope.contract_addr.clone(), + query_data: msg, + }) + .await?; + let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(QueryWasmOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/execute/mod.rs similarity index 75% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs rename to packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/execute/mod.rs index 9a2d786f1..11742a2e8 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/execute/mod.rs @@ -4,14 +4,17 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::common::CliCoins; +use crate::{commands::transaction::CosmosContext, types::CliCoins}; -use super::{msg_type, CwActionContext}; +use super::super::msg_type; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = CwActionContext)] +#[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = ExecuteWasmOutput)] -pub struct ExecuteCommands { +/// Execute contract method +pub struct ExecuteContractCommands { + /// Contract address + contract_addr: String, #[interactive_clap(value_enum)] #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? @@ -26,14 +29,14 @@ pub struct ExecuteCommands { signer: String, } -impl ExecuteCommands { +impl ExecuteContractCommands { fn input_msg_type( - _context: &CwActionContext, + _context: &CosmosContext, ) -> color_eyre::eyre::Result> { msg_type::input_msg_type() } - fn input_coins(_context: &CwActionContext) -> color_eyre::eyre::Result> { + fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) .wrap_err("Bad coins input") @@ -43,8 +46,8 @@ pub struct ExecuteWasmOutput; impl ExecuteWasmOutput { fn from_previous_context( - previous_context: CwActionContext, - scope:&::InteractiveClapContextScope, + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { // TODO: non-panic parse_network let chain = parse_network(&previous_context.chain_id); @@ -62,7 +65,7 @@ impl ExecuteWasmOutput { let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: previous_context.contract_addr.parse()?, + contract: scope.contract_addr.parse()?, msg, funds: coins, }; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs new file mode 100644 index 000000000..645ce9437 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs @@ -0,0 +1,110 @@ +use color_eyre::eyre::Context; +use cw_orch::{ + prelude::{networks::parse_network, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use crate::{ + commands::transaction::CosmosContext, + types::{CliCoins, CliSkippable}, +}; + +use super::super::msg_type; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = InstantiateWasmOutput)] +/// Execute contract method +pub struct InstantiateContractCommands { + /// Contract code id + code_id: u64, + #[interactive_clap(value_enum)] + #[interactive_clap(skip_default_input_arg)] + /// How do you want to pass the message arguments? + msg_type: msg_type::MsgType, + /// Enter message + msg: String, + #[interactive_clap(skip_default_input_arg)] + /// Admin address of the contract + admin: CliSkippable, + #[interactive_clap(skip_default_input_arg)] + /// Label for the contract + label: CliSkippable, + #[interactive_clap(skip_default_input_arg)] + /// Input coins + coins: CliCoins, + /// Signer id + // TODO: should be possible to sign it from the seed phrase + signer: String, +} + +impl InstantiateContractCommands { + fn input_msg_type( + _context: &CosmosContext, + ) -> color_eyre::eyre::Result> { + msg_type::input_msg_type() + } + + fn input_admin( + _context: &CosmosContext, + ) -> color_eyre::eyre::Result>> { + let val: Option = + inquire::CustomType::new("Input admin address for the contract".to_string().as_str()) + .with_help_message("press Esc to skip admin") + .prompt_skippable()?; + Ok(Some(CliSkippable(val))) + } + + fn input_label( + _context: &CosmosContext, + ) -> color_eyre::eyre::Result>> { + let val: Option = + inquire::CustomType::new("Input label for the contract".to_string().as_str()) + .with_help_message("press Esc to skip label") + .prompt_skippable()?; + Ok(Some(CliSkippable(val))) + } + + fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::parse_coins() + .map(|c| Some(CliCoins(c))) + .wrap_err("Bad coins input") + } +} +pub struct InstantiateWasmOutput; + +impl InstantiateWasmOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + // TODO: non-panic parse_network + let chain = parse_network(&previous_context.chain_id); + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let coins = (&scope.coins).try_into()?; + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; + + let rt = Runtime::new()?; + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgInstantiateContract { + sender: daemon.sender.pub_addr()?, + admin: scope.admin.clone().0.map(|a| a.parse()).transpose()?, + code_id: scope.code_id, + label: scope.label.0.clone(), + msg, + funds: coins, + }; + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(InstantiateWasmOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs new file mode 100644 index 000000000..7247d7e14 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs @@ -0,0 +1,30 @@ +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +use crate::commands::transaction::CosmosContext; + +mod execute; +mod instantiate; +mod store; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(context = CosmosContext)] +pub struct TxCommands { + #[interactive_clap(subcommand)] + action: TxAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = CosmosContext)] +/// Select cosmwasm action +pub enum TxAction { + /// Store contract + #[strum_discriminants(strum(message = "Store contract"))] + Store(store::StoreContractCommands), + /// Instantiate contract + #[strum_discriminants(strum(message = "Instantiate contract"))] + Instantiate(instantiate::InstantiateContractCommands), + /// Execute contract method + #[strum_discriminants(strum(message = "Execute contract method"))] + Execute(execute::ExecuteContractCommands), +} diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs new file mode 100644 index 000000000..de317e0ff --- /dev/null +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs @@ -0,0 +1,62 @@ +use color_eyre::eyre::Context; +use cw_orch::{ + prelude::{networks::parse_network, DaemonAsync, IndexResponse}, + tokio::runtime::Runtime, +}; + +use crate::commands::transaction::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = StoreWasmOutput)] +/// Execute contract method +pub struct StoreContractCommands { + /// Input path to the wasm + wasm_path: crate::types::PathBuf, + /// Signer id + // TODO: should be possible to sign it from the seed phrase + signer: String, +} + +pub struct StoreWasmOutput; + +impl StoreWasmOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + // TODO: non-panic parse_network + let chain = parse_network(&previous_context.chain_id); + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let wasm_byte_code = std::fs::read(&scope.wasm_path).wrap_err(format!( + "Failed to open or read the file: {}", + scope.wasm_path.0.display() + ))?; + + let rt = Runtime::new()?; + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgStoreCode { + sender: daemon.sender.pub_addr()?, + wasm_byte_code, + instantiate_permission: None, + }; + let result = daemon.sender.commit_tx(vec![exec_msg], None).await?; + + println!("Uploaded: {:?}", result.txhash); + + let code_id = result.uploaded_code_id().unwrap(); + + println!("code_id: {code_id}"); + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(StoreWasmOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/transaction/mod.rs index 128769a85..6d816fcba 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/mod.rs @@ -4,41 +4,41 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] -#[interactive_clap(output_context = TxContext)] -pub struct TxCommands { +#[interactive_clap(output_context = CosmosContext)] +pub struct CosmosCommands { /// Chain id chain_id: String, #[interactive_clap(subcommand)] - action: TxAction, + action: CosmosAction, } #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = TxContext)] -/// Select type of transaction -pub enum TxAction { +#[interactive_clap(context = CosmosContext)] +/// Select type of cosmos action +pub enum CosmosAction { /// Cosmwasm Action #[strum_discriminants(strum(message = "Perform CosmWasm action"))] Cw(cosmwasm_tx::CwCommands), } -impl From for () { - fn from(_value: TxContext) -> Self { +impl From for () { + fn from(_value: CosmosContext) -> Self { () } } #[derive(Clone)] -pub struct TxContext { +pub struct CosmosContext { chain_id: String, } -impl TxContext { +impl CosmosContext { fn from_previous_context( _previous_context: (), - scope:&::InteractiveClapContextScope, + scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - Ok(TxContext { + Ok(CosmosContext { chain_id: scope.chain_id.clone(), }) } diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 23a30bcaf..8ac0b60c1 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -1,53 +1,14 @@ pub use base64::prelude::BASE64_STANDARD as B64; use base64::Engine; use inquire::{error::InquireResult, InquireError}; -use interactive_clap::ToCli; use keyring::Entry; pub fn entry_for_seed(name: &str) -> keyring::Result { Entry::new_with_target("cw-orch", "cw-cli", name) } -#[derive(Default, PartialEq, Eq, Debug, Clone)] -pub struct CliCoins(pub cosmwasm_std::Coins); - -impl TryFrom<&CliCoins> for Vec { - type Error = color_eyre::Report; - - fn try_from(value: &CliCoins) -> Result { - value - .0 - .iter() - .map(|cosmwasm_std::Coin { amount, denom }| { - Ok(cosmrs::Coin { - amount: amount.u128(), - denom: denom.parse()?, - }) - }) - .collect() - } -} - -impl std::fmt::Display for CliCoins { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) - } -} - -impl std::str::FromStr for CliCoins { - type Err = String; - fn from_str(s: &str) -> Result { - let coins = cosmwasm_std::Coins::from_str(s).map_err(|e| e.to_string())?; - Ok(CliCoins(coins)) - } -} - -impl ToCli for CliCoins { - type CliVariant = CliCoins; -} - pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { - let entry = entry_for_seed(&name)?; + let entry = entry_for_seed(name)?; let password = entry.get_password()?; let phrase = String::from_utf8(B64.decode(password)?)?; Ok(phrase) diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index b712ea933..cf9550fc4 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,5 +1,6 @@ mod commands; mod common; +mod types; use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] diff --git a/packages/cw-orch-cli/src/types/coins.rs b/packages/cw-orch-cli/src/types/coins.rs new file mode 100644 index 000000000..36df598f4 --- /dev/null +++ b/packages/cw-orch-cli/src/types/coins.rs @@ -0,0 +1,29 @@ +#[derive(Default, PartialEq, Eq, Debug, Clone, derive_more::FromStr)] +pub struct CliCoins(pub cosmwasm_std::Coins); + +impl TryFrom<&CliCoins> for Vec { + type Error = color_eyre::Report; + + fn try_from(value: &CliCoins) -> Result { + value + .0 + .iter() + .map(|cosmwasm_std::Coin { amount, denom }| { + Ok(cosmrs::Coin { + amount: amount.u128(), + denom: denom.parse()?, + }) + }) + .collect() + } +} + +impl std::fmt::Display for CliCoins { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl interactive_clap::ToCli for CliCoins { + type CliVariant = CliCoins; +} diff --git a/packages/cw-orch-cli/src/types/mod.rs b/packages/cw-orch-cli/src/types/mod.rs new file mode 100644 index 000000000..ffce61008 --- /dev/null +++ b/packages/cw-orch-cli/src/types/mod.rs @@ -0,0 +1,7 @@ +mod coins; +mod path_buf; +mod skippable; + +pub use coins::CliCoins; +pub use path_buf::PathBuf; +pub use skippable::CliSkippable; diff --git a/packages/cw-orch-cli/src/types/path_buf.rs b/packages/cw-orch-cli/src/types/path_buf.rs new file mode 100644 index 000000000..eb85c4b86 --- /dev/null +++ b/packages/cw-orch-cli/src/types/path_buf.rs @@ -0,0 +1,21 @@ +#[derive( + Debug, + Default, + Clone, + derive_more::AsRef, + derive_more::From, + derive_more::Into, + derive_more::FromStr, +)] +#[as_ref(forward)] +pub struct PathBuf(pub std::path::PathBuf); + +impl std::fmt::Display for PathBuf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.display()) + } +} + +impl interactive_clap::ToCli for PathBuf { + type CliVariant = PathBuf; +} diff --git a/packages/cw-orch-cli/src/types/skippable.rs b/packages/cw-orch-cli/src/types/skippable.rs new file mode 100644 index 000000000..91189e807 --- /dev/null +++ b/packages/cw-orch-cli/src/types/skippable.rs @@ -0,0 +1,33 @@ +#[derive(Default, PartialEq, Eq, Debug, Clone)] +pub struct CliSkippable(pub Option); + +impl std::fmt::Display for CliSkippable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.0 { + Some(s) => s.fmt(f), + None => Ok(()), + } + } +} + +impl std::str::FromStr for CliSkippable +where + T: std::str::FromStr, + T::Err: std::fmt::Debug, +{ + type Err = String; + fn from_str(s: &str) -> Result { + if s.is_empty() { + Ok(CliSkippable(None)) + } else { + match T::from_str(s) { + Ok(output) => Ok(CliSkippable(Some(output))), + Err(e) => Err(format!("{e:?}")), + } + } + } +} + +impl interactive_clap::ToCli for CliSkippable { + type CliVariant = CliSkippable; +} From a55856b8b88afc8e76457fe5988d4277dd9317dc Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 10 Nov 2023 15:20:37 +0200 Subject: [PATCH 037/135] small renames --- packages/cw-orch-cli/src/commands/keys/mod.rs | 2 +- packages/cw-orch-cli/src/commands/mod.rs | 2 +- .../src/commands/transaction/cosmwasm_tx/query/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/keys/mod.rs b/packages/cw-orch-cli/src/commands/keys/mod.rs index beda9a534..63d587c66 100644 --- a/packages/cw-orch-cli/src/commands/keys/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/mod.rs @@ -17,7 +17,7 @@ pub enum KeyAction { /// Add key to the keyring #[strum_discriminants(strum(message = "Add key to the keyring"))] Add(add_key::AddKeyCommand), - /// Show key from keyring + /// Show seed from keyring #[strum_discriminants(strum(message = "Show key of given id from the keyring"))] Show(show_key::ShowKeyCommand), /// Remove key from the keyring diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index bf1198eb0..8af3fb832 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -9,7 +9,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; pub enum Commands { /// Construct action #[strum_discriminants(strum(message = "Construct action"))] - Tx(transaction::CosmosCommands), + Action(transaction::CosmosCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "Manage keys"))] Key(keys::KeyCommands), diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs index 713fadc71..15d3b7c24 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs +++ b/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs @@ -18,5 +18,5 @@ pub struct QueryCommands { pub enum QueryAction { /// Query wasm smart #[strum_discriminants(strum(message = "Query wasm smart"))] - Query(query_contract_smart::QuerySmartCommands), + Smart(query_contract_smart::QuerySmartCommands), } From a48f9f820389f0d56cb3d1cb5868af604a3dacfd Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 10 Nov 2023 16:54:51 +0200 Subject: [PATCH 038/135] rename actions as actions --- .../cosmwasm_tx/mod.rs | 0 .../cosmwasm_tx/msg_type/mod.rs | 0 .../cosmwasm_tx/query/mod.rs | 2 +- .../query/query_contract_smart/mod.rs | 2 +- .../cosmwasm_tx/tx/execute/mod.rs | 2 +- .../cosmwasm_tx/tx/instantiate/mod.rs | 26 +++++-------- .../cosmwasm_tx/tx/mod.rs | 2 +- .../cosmwasm_tx/tx/store/mod.rs | 2 +- .../commands/{transaction => action}/mod.rs | 4 +- packages/cw-orch-cli/src/commands/keys/mod.rs | 4 ++ .../src/commands/keys/show_address/mod.rs | 37 +++++++++++++++++++ packages/cw-orch-cli/src/commands/mod.rs | 4 +- 12 files changed, 58 insertions(+), 27 deletions(-) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/mod.rs (100%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/msg_type/mod.rs (100%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/query/mod.rs (92%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/query/query_contract_smart/mod.rs (97%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/tx/execute/mod.rs (97%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/tx/instantiate/mod.rs (81%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/tx/mod.rs (95%) rename packages/cw-orch-cli/src/commands/{transaction => action}/cosmwasm_tx/tx/store/mod.rs (97%) rename packages/cw-orch-cli/src/commands/{transaction => action}/mod.rs (94%) create mode 100644 packages/cw-orch-cli/src/commands/keys/show_address/mod.rs diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/msg_type/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/msg_type/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/msg_type/mod.rs diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs similarity index 92% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs index 15d3b7c24..2685c2f8f 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs @@ -1,6 +1,6 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::commands::transaction::CosmosContext; +use crate::commands::action::CosmosContext; mod query_contract_smart; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs similarity index 97% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs index ead73ce53..cc9aee198 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/query/query_contract_smart/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs @@ -7,7 +7,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::commands::transaction::CosmosContext; +use crate::commands::action::CosmosContext; use super::super::msg_type; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs similarity index 97% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/execute/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs index 11742a2e8..92f7c9cdd 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs @@ -4,7 +4,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::{commands::transaction::CosmosContext, types::CliCoins}; +use crate::{commands::action::CosmosContext, types::CliCoins}; use super::super::msg_type; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs similarity index 81% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs index 645ce9437..dfca20f5a 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/instantiate/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs @@ -1,11 +1,11 @@ use color_eyre::eyre::Context; use cw_orch::{ - prelude::{networks::parse_network, DaemonAsync}, + prelude::{networks::parse_network, DaemonAsync, IndexResponse}, tokio::runtime::Runtime, }; use crate::{ - commands::transaction::CosmosContext, + commands::action::CosmosContext, types::{CliCoins, CliSkippable}, }; @@ -24,13 +24,12 @@ pub struct InstantiateContractCommands { msg_type: msg_type::MsgType, /// Enter message msg: String, + /// Label for the contract + label: String, #[interactive_clap(skip_default_input_arg)] /// Admin address of the contract admin: CliSkippable, #[interactive_clap(skip_default_input_arg)] - /// Label for the contract - label: CliSkippable, - #[interactive_clap(skip_default_input_arg)] /// Input coins coins: CliCoins, /// Signer id @@ -55,16 +54,6 @@ impl InstantiateContractCommands { Ok(Some(CliSkippable(val))) } - fn input_label( - _context: &CosmosContext, - ) -> color_eyre::eyre::Result>> { - let val: Option = - inquire::CustomType::new("Input label for the contract".to_string().as_str()) - .with_help_message("press Esc to skip label") - .prompt_skippable()?; - Ok(Some(CliSkippable(val))) - } - fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) @@ -96,11 +85,14 @@ impl InstantiateWasmOutput { sender: daemon.sender.pub_addr()?, admin: scope.admin.clone().0.map(|a| a.parse()).transpose()?, code_id: scope.code_id, - label: scope.label.0.clone(), + label: Some(scope.label.clone()), msg, funds: coins, }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let address = res.instantiated_contract_address()?; + + println!("Address of the instantiated contract: {address}"); color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/mod.rs similarity index 95% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/mod.rs index 7247d7e14..cf7f73021 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/mod.rs @@ -1,6 +1,6 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::commands::transaction::CosmosContext; +use crate::commands::action::CosmosContext; mod execute; mod instantiate; diff --git a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs similarity index 97% rename from packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs index de317e0ff..28808d8c0 100644 --- a/packages/cw-orch-cli/src/commands/transaction/cosmwasm_tx/tx/store/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs @@ -4,7 +4,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::commands::transaction::CosmosContext; +use crate::commands::action::CosmosContext; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] diff --git a/packages/cw-orch-cli/src/commands/transaction/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs similarity index 94% rename from packages/cw-orch-cli/src/commands/transaction/mod.rs rename to packages/cw-orch-cli/src/commands/action/mod.rs index 6d816fcba..e45237eb4 100644 --- a/packages/cw-orch-cli/src/commands/transaction/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -23,9 +23,7 @@ pub enum CosmosAction { } impl From for () { - fn from(_value: CosmosContext) -> Self { - () - } + fn from(_value: CosmosContext) -> Self {} } #[derive(Clone)] diff --git a/packages/cw-orch-cli/src/commands/keys/mod.rs b/packages/cw-orch-cli/src/commands/keys/mod.rs index 63d587c66..0f089287a 100644 --- a/packages/cw-orch-cli/src/commands/keys/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/mod.rs @@ -1,5 +1,6 @@ mod add_key; mod remove_key; +mod show_address; mod show_key; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; @@ -23,4 +24,7 @@ pub enum KeyAction { /// Remove key from the keyring #[strum_discriminants(strum(message = "Remove key from the keyring"))] Remove(remove_key::RemoveKeyCommand), + /// Show address of the key + #[strum_discriminants(strum(message = "Show address of the key"))] + ShowAddress(show_address::ShowAddressCommand), } diff --git a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs new file mode 100644 index 000000000..eba63fff6 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -0,0 +1,37 @@ +use cw_orch::{ + prelude::{networks::parse_network, Daemon, TxHandler}, + tokio::runtime::Runtime, +}; + +use crate::common::seed_phrase_for_id; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = ShowAddressOutput)] +pub struct ShowAddressCommand { + /// Id of the key + name: String, + chain_id: String, +} + +pub struct ShowAddressOutput; + +impl ShowAddressOutput { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let mnemonic = seed_phrase_for_id(&scope.name)?; + let chain = parse_network(&scope.chain_id); + + let rt = Runtime::new()?; + let daemon = Daemon::builder() + .handle(rt.handle()) + .chain(chain) + .mnemonic(mnemonic) + .build()?; + let address = daemon.sender(); + println!("Your address: {address}"); + Ok(ShowAddressOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index 8af3fb832..e207bc8e4 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -1,5 +1,5 @@ +mod action; mod keys; -mod transaction; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; @@ -9,7 +9,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; pub enum Commands { /// Construct action #[strum_discriminants(strum(message = "Construct action"))] - Action(transaction::CosmosCommands), + Action(action::CosmosCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "Manage keys"))] Key(keys::KeyCommands), From 63f0f880e45e7cf8244c941c84bbadc7f532fcf8 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 10 Nov 2023 17:20:15 +0200 Subject: [PATCH 039/135] taplo fmt --- contracts/counter/src/interface.rs | 13 +++++++++++++ contracts/counter/src/lib.rs | 16 +--------------- packages/cw-orch-cli/Cargo.toml | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/contracts/counter/src/interface.rs b/contracts/counter/src/interface.rs index 89e15635a..0d5ad5313 100644 --- a/contracts/counter/src/interface.rs +++ b/contracts/counter/src/interface.rs @@ -63,3 +63,16 @@ impl CounterContract { } } // ANCHOR_END: daemon + +// ANCHOR: cli +use cw_orch_cli::OrchCliResult; + +impl cw_orch_cli::CwCliAddons for CounterContract { + fn addons(&mut self, _context: Empty) -> OrchCliResult<()> + where + Self: cw_orch::prelude::ContractInstance, + { + Ok(()) + } +} +// ANCHOR_END diff --git a/contracts/counter/src/lib.rs b/contracts/counter/src/lib.rs index 48e6476e2..b2bc283cb 100644 --- a/contracts/counter/src/lib.rs +++ b/contracts/counter/src/lib.rs @@ -17,19 +17,5 @@ pub use crate::msg::{ExecuteMsgFns as CounterExecuteMsgFns, QueryMsgFns as Count // ANCHOR: custom_interface #[cfg(feature = "interface")] -mod interface { - use cosmwasm_std::Empty; - use cw_orch_cli::OrchCliResult; - - use crate::CounterContract; - - impl cw_orch_cli::CwCliAddons for CounterContract { - fn addons(&mut self, _context: Empty) -> OrchCliResult<()> - where - Self: cw_orch::prelude::ContractInstance, - { - Ok(()) - } - } -} +mod interface; // ANCHOR_END: custom_interface diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 451577ef8..48e14d821 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -33,4 +33,4 @@ log = "0.4.14" shell-words = "1.0.0" tonic = "0.10.0" -derive_more = "0.99" \ No newline at end of file +derive_more = "0.99" From bf2747e3720c2c8c7294b8e482fac3e2a9baf092 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 17 Nov 2023 15:46:39 +0200 Subject: [PATCH 040/135] add chain selector --- .../cw-orch-cli/src/commands/action/mod.rs | 22 ++++++++ packages/cw-orch-networks/src/networks/mod.rs | 55 ++++++++++--------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index e45237eb4..de2be671c 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -1,11 +1,14 @@ mod cosmwasm_tx; +use cw_orch::daemon::networks::NETWORKS; +use inquire::Select; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = CosmosContext)] pub struct CosmosCommands { + #[interactive_clap(skip_default_input_arg)] /// Chain id chain_id: String, #[interactive_clap(subcommand)] @@ -22,6 +25,25 @@ pub enum CosmosAction { Cw(cosmwasm_tx::CwCommands), } +impl CosmosCommands { + fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { + let chain_ids: Vec<_> = NETWORKS + .iter() + .map(|network| { + format!( + "{} {}({})", + network.network_info.id.to_uppercase(), + network.kind.to_string().to_uppercase(), + network.chain_id + ) + }) + .collect(); + let selected = Select::new("Select chain", chain_ids).raw_prompt()?; + let chain_id = NETWORKS[selected.index].chain_id.to_owned(); + Ok(Some(chain_id)) + } +} + impl From for () { fn from(_value: CosmosContext) -> Self {} } diff --git a/packages/cw-orch-networks/src/networks/mod.rs b/packages/cw-orch-networks/src/networks/mod.rs index 267d5faf6..7c1db3283 100644 --- a/packages/cw-orch-networks/src/networks/mod.rs +++ b/packages/cw-orch-networks/src/networks/mod.rs @@ -43,34 +43,35 @@ pub fn parse_network(net_id: &str) -> ChainInfo { } pub fn parse_network_safe(net_id: &str) -> Result { - let networks = vec![ - UNI_6, - JUNO_1, - LOCAL_JUNO, - PISCO_1, - PHOENIX_1, - LOCAL_TERRA, - INJECTIVE_888, - CONSTANTINE_3, - ARCHWAY_1, - PION_1, - NARWHAL_1, - NEUTRON_1, - INJECTIVE_1, - HARPOON_4, - OSMOSIS_1, - OSMO_5, - LOCAL_OSMO, - LOCAL_MIGALOO, - LOCAL_NEUTRON, - MIGALOO_1, - LOCAL_SEI, - SEI_DEVNET_3, - ATLANTIC_2, - PACIFIC_1, - ]; - networks + NETWORKS .into_iter() .find(|net| net.chain_id == net_id) .ok_or(format!("Network not found: {}", net_id)) } + +pub const NETWORKS: [ChainInfo<'_>; 24] = [ + UNI_6, + JUNO_1, + LOCAL_JUNO, + PISCO_1, + PHOENIX_1, + LOCAL_TERRA, + INJECTIVE_888, + CONSTANTINE_3, + ARCHWAY_1, + PION_1, + NARWHAL_1, + NEUTRON_1, + INJECTIVE_1, + HARPOON_4, + OSMOSIS_1, + OSMO_5, + LOCAL_OSMO, + LOCAL_MIGALOO, + LOCAL_NEUTRON, + MIGALOO_1, + LOCAL_SEI, + SEI_DEVNET_3, + ATLANTIC_2, + PACIFIC_1, +]; From 6c036ce09614a47dce808fa7a619b6bbab6b3698 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 17 Nov 2023 18:42:23 +0200 Subject: [PATCH 041/135] transfers --- packages/cw-orch-cli/Cargo.toml | 1 + .../src/commands/action/cosmwasm_tx/mod.rs | 17 ----- .../action/cosmwasm_tx/tx/execute/mod.rs | 9 ++- .../cw-orch-cli/src/commands/action/mod.rs | 4 ++ .../commands/action/transfer_tx/cw20/mod.rs | 61 +++++++++++++++++ .../src/commands/action/transfer_tx/mod.rs | 27 ++++++++ .../commands/action/transfer_tx/native/mod.rs | 65 +++++++++++++++++++ 7 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 48e14d821..256f78f32 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -18,6 +18,7 @@ base64 = { version = "0.21.0" } # TO cosmwasm-std = { version = "1.3" } cw-orch = { path = "../../cw-orch", features = ["daemon"] } cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } +cw20 = { workspace = true } interactive-clap = "0.2.4" interactive-clap-derive = "0.2.4" clap = { version = "4.0.18", features = ["derive"] } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs index a8d1beb45..cdb7b47e8 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs @@ -25,20 +25,3 @@ pub enum CwAction { #[strum_discriminants(strum(message = "Query"))] Query(query::QueryCommands), } - -// TODO: remove if unused -// #[derive(Clone)] -// pub struct CwActionContext { -// chain_id: String, -// } - -// impl CwActionContext { -// fn from_previous_context( -// previous_context: TxContext, -// scope:&::InteractiveClapContextScope, -// ) -> color_eyre::eyre::Result { -// Ok(CwActionContext { -// chain_id: previous_context.chain_id.clone(), -// }) -// } -// } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs index 92f7c9cdd..69d245610 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs @@ -1,7 +1,6 @@ -use color_eyre::eyre::Context; +use color_eyre::eyre::{self, Context}; use cw_orch::{ - prelude::{networks::parse_network, DaemonAsync}, - tokio::runtime::Runtime, + daemon::networks::parse_network_safe, prelude::DaemonAsync, tokio::runtime::Runtime, }; use crate::{commands::action::CosmosContext, types::CliCoins}; @@ -49,8 +48,8 @@ impl ExecuteWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id); + let chain = + parse_network_safe(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index de2be671c..e5dfea7a6 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -1,4 +1,5 @@ mod cosmwasm_tx; +mod transfer_tx; use cw_orch::daemon::networks::NETWORKS; use inquire::Select; @@ -23,6 +24,9 @@ pub enum CosmosAction { /// Cosmwasm Action #[strum_discriminants(strum(message = "Perform CosmWasm action"))] Cw(cosmwasm_tx::CwCommands), + // /// Transfer Action + #[strum_discriminants(strum(message = "Perform Transfer action"))] + Transfer(transfer_tx::TransferCommands), } impl CosmosCommands { diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs new file mode 100644 index 000000000..0500d88e1 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs @@ -0,0 +1,61 @@ +use color_eyre::eyre; +use cosmwasm_std::Uint128; +use cw_orch::{ + daemon::{networks::parse_network_safe, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use super::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = TransferCw20Output)] +pub struct Cw20TransferCommands { + /// Cw20 Address + cw20_address: String, + /// Cw20 Amount + amount: u128, + /// Recipient + to_address: String, + /// Signer id + signer: String, +} + +pub struct TransferCw20Output; + +impl TransferCw20Output { + fn from_previous_context( + previous_context: CosmosContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = + parse_network_safe(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { + recipient: scope.to_address.clone(), + amount: Uint128::new(scope.amount), + }; + let msg = serde_json::to_vec(&cw20_msg)?; + let rt = Runtime::new()?; + + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender.pub_addr()?, + contract: scope.cw20_address.parse()?, + msg, + funds: vec![], + }; + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(TransferCw20Output) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs new file mode 100644 index 000000000..7b7c2a040 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs @@ -0,0 +1,27 @@ +mod cw20; +mod native; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +use super::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(context = CosmosContext)] +pub struct TransferCommands { + #[interactive_clap(subcommand)] + action: TransferAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = CosmosContext)] +/// Select cosmwasm action +pub enum TransferAction { + /// Transfer native coins + #[strum_discriminants(strum(message = "Transfer native coins"))] + Native(native::NativeTransferCommands), + /// Transfer cw20 coin + #[strum_discriminants(strum(message = "Transfer cw20 coin"))] + Cw20(cw20::Cw20TransferCommands), + // TODO: cw720? +} diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs new file mode 100644 index 000000000..b5ff2947d --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs @@ -0,0 +1,65 @@ +use color_eyre::eyre::{self, Context}; +use cw_orch::{ + daemon::{networks::parse_network_safe, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use crate::types::CliCoins; + +use super::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = TransferNativeOutput)] +pub struct NativeTransferCommands { + #[interactive_clap(skip_default_input_arg)] + /// Input coins + coins: CliCoins, + /// Recipient + to_address: String, + /// Signer id + signer: String, +} + +impl NativeTransferCommands { + fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::parse_coins() + .map(|c| Some(CliCoins(c))) + .wrap_err("Bad coins input") + } +} + +pub struct TransferNativeOutput; + +impl TransferNativeOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = + parse_network_safe(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let coins: Vec = (&scope.coins).try_into()?; + + let rt = Runtime::new()?; + + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(seed) + .build() + .await?; + + let transfer_msg = cosmrs::bank::MsgSend { + from_address: daemon.sender.pub_addr()?, + to_address: scope.to_address.parse()?, + amount: coins, + }; + let _res = daemon.sender.commit_tx(vec![transfer_msg], None).await?; + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(TransferNativeOutput) + } +} From 489e6721e10de91b715a0308358272b5e5dd8518 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 1 Dec 2023 16:59:30 +0200 Subject: [PATCH 042/135] get and transfer ownership cw-ownable --- packages/cw-orch-cli/Cargo.toml | 3 + .../action/cosmwasm_tx/cw_ownable/get/mod.rs | 54 +++++++++++ .../action/cosmwasm_tx/cw_ownable/mod.rs | 49 ++++++++++ .../cosmwasm_tx/cw_ownable/transfer/mod.rs | 91 +++++++++++++++++++ .../src/commands/action/cosmwasm_tx/mod.rs | 4 + packages/cw-orch-cli/src/common.rs | 32 +++++++ packages/cw-orch-cli/src/types/expiration.rs | 42 +++++++++ packages/cw-orch-cli/src/types/mod.rs | 2 + 8 files changed, 277 insertions(+) create mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs create mode 100644 packages/cw-orch-cli/src/types/expiration.rs diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 256f78f32..f47c38a9f 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -16,6 +16,7 @@ cosmrs = "0.14.0" rand_core = { version = "0.6", features = ["std"] } base64 = { version = "0.21.0" } # TODO: move to workspace cosmwasm-std = { version = "1.3" } +cw-utils = "1.0.3" cw-orch = { path = "../../cw-orch", features = ["daemon"] } cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } cw20 = { workspace = true } @@ -35,3 +36,5 @@ shell-words = "1.0.0" tonic = "0.10.0" derive_more = "0.99" + +cw-ownable = { version = "0.5.1" } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs new file mode 100644 index 000000000..144069132 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs @@ -0,0 +1,54 @@ +use cw_orch::{ + daemon::{networks::parse_network, ChainRegistryData, GrpcChannel}, + tokio::runtime::Runtime, +}; + +use cosmrs::proto::cosmwasm::wasm::v1::{ + query_client::QueryClient, QuerySmartContractStateRequest, +}; + +use crate::commands::action::CosmosContext; + +use super::ContractQueryMsg; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = GetOwnershipOutput)] +pub struct GetOwnership { + /// Contract address + contract_addr: String, +} + +pub struct GetOwnershipOutput; + +impl GetOwnershipOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network(&previous_context.chain_id); + let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; + let chain_data: ChainRegistryData = chain.into(); + + let rt = Runtime::new()?; + rt.block_on(async { + let grpc_channel = + GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + let mut client = QueryClient::new(grpc_channel); + + // TODO: support other types of queries + // It should be possible to support `Any` on query + let resp = client + .smart_contract_state(QuerySmartContractStateRequest { + address: scope.contract_addr.clone(), + query_data: msg, + }) + .await?; + let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(GetOwnershipOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs new file mode 100644 index 000000000..88dce2689 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs @@ -0,0 +1,49 @@ +use serde::Serialize; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +use crate::commands::action::CosmosContext; + +mod get; +mod transfer; + +// Helper enum to serialize execute +#[derive(Serialize)] +#[serde(rename_all = "snake_case")] +enum ContractExecuteMsg { + UpdateOwnership(cw_ownable::Action), +} + +// Helper enum to serialize query +#[derive(Serialize)] +#[serde(rename_all = "snake_case")] +enum ContractQueryMsg { + Ownership {}, +} + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(context = CosmosContext)] +pub struct CwOwnableCommands { + #[interactive_clap(subcommand)] + action: CwOwnableAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = CosmosContext)] +/// Select cosmwasm action +pub enum CwOwnableAction { + /// Propose to transfer contract ownership to another address + #[strum_discriminants(strum( + message = "Propose to transfer contract ownership to another address." + ))] + Transfer(transfer::TransferOwnership), + // /// Accept pending ownership + // #[strum_discriminants(strum(message = "Accept pending ownership."))] + // Accept(accept::AcceptOwnership), + // /// Renounce pending ownership + // #[strum_discriminants(strum(message = "Renounce pending ownership"))] + // Renounce(renounce::RenounceOwnership), + /// Get current ownership + #[strum_discriminants(strum(message = "Get current ownership"))] + Get(get::GetOwnership), +} diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs new file mode 100644 index 000000000..ca93810ad --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs @@ -0,0 +1,91 @@ +use cw_orch::{ + daemon::{networks::parse_network, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use crate::{ + commands::action::CosmosContext, + common::parse_expiration, + types::{CliExpiration, CliSkippable}, +}; + +use super::ContractExecuteMsg; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = TransferOwnershipOutput)] +pub struct TransferOwnership { + /// Contract address + contract_addr: String, + /// New owner address + new_owner: String, + /// Expiration + #[interactive_clap(skip_default_input_arg)] + expiration: CliExpiration, + /// Signer id + // TODO: should be possible to sign it from the seed phrase + signer: String, + /// New owner signer id + #[interactive_clap(skip_default_input_arg)] + new_signer: CliSkippable, +} + +impl TransferOwnership { + fn input_expiration(_: &CosmosContext) -> color_eyre::eyre::Result> { + let expiration = parse_expiration()?; + Ok(Some(CliExpiration(expiration))) + } + + fn input_new_signer( + _: &CosmosContext, + ) -> color_eyre::eyre::Result>> { + let new_signer = inquire::Text::new("New signer id") + .with_help_message("Press ESC to skip auto-claim") + .prompt_skippable()?; + Ok(Some(CliSkippable(new_signer))) + } +} + +pub struct TransferOwnershipOutput; + +impl TransferOwnershipOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network(&previous_context.chain_id); + let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let receiver_seed = scope + .new_signer + .0 + .as_deref() + .map(|new_signer| crate::common::seed_phrase_for_id(new_signer)) + .transpose()?; + let action = cw_ownable::Action::TransferOwnership { + new_owner: scope.new_owner.clone(), + expiry: Some(scope.expiration.0), + }; + let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; + + let rt = Runtime::new()?; + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(sender_seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender.pub_addr()?, + contract: scope.contract_addr.parse()?, + msg, + funds: vec![], + }; + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(TransferOwnershipOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs index cdb7b47e8..2bf0e8092 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs @@ -1,3 +1,4 @@ +mod cw_ownable; pub mod msg_type; mod query; mod tx; @@ -24,4 +25,7 @@ pub enum CwAction { /// Query #[strum_discriminants(strum(message = "Query"))] Query(query::QueryCommands), + /// CW-Ownable Action + #[strum_discriminants(strum(message = "CW-Ownable action"))] + CwOwnable(cw_ownable::CwOwnableCommands), } diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 8ac0b60c1..574c83c91 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -35,3 +35,35 @@ pub fn parse_coins() -> InquireResult { } Ok(coins) } + +#[derive(Clone, Copy, strum::EnumIter, strum::EnumString, derive_more::Display)] +pub enum ExpirationType { + AtHeight, + AtTime, + Never, +} + +impl ExpirationType { + const VARIANTS: &'static [ExpirationType] = &[Self::AtHeight, Self::AtTime, Self::Never]; +} + +pub fn parse_expiration() -> InquireResult { + let locked = inquire::Select::new("Choose expiration type", ExpirationType::VARIANTS.to_vec()) + .prompt_skippable()? + .unwrap_or(ExpirationType::Never); + + let expiration = match locked { + ExpirationType::AtHeight => { + let block_height = inquire::CustomType::::new("Input block height").prompt()?; + cw_utils::Expiration::AtHeight(block_height) + } + ExpirationType::AtTime => { + let timestamp_nanos = + inquire::CustomType::::new("Input timestamp in nanos").prompt()?; + let timestamp = cosmwasm_std::Timestamp::from_nanos(timestamp_nanos); + cw_utils::Expiration::AtTime(timestamp) + } + ExpirationType::Never => cw_utils::Expiration::Never {}, + }; + Ok(expiration) +} diff --git a/packages/cw-orch-cli/src/types/expiration.rs b/packages/cw-orch-cli/src/types/expiration.rs new file mode 100644 index 000000000..d6fa874ca --- /dev/null +++ b/packages/cw-orch-cli/src/types/expiration.rs @@ -0,0 +1,42 @@ +use std::str::FromStr; + +use cosmwasm_std::Timestamp; +use cw_utils::Expiration; + +#[derive(Debug, Default, Clone, derive_more::AsRef, derive_more::From, derive_more::Into)] +#[as_ref(forward)] +pub struct CliExpiration(pub Expiration); + +impl std::fmt::Display for CliExpiration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl interactive_clap::ToCli for CliExpiration { + type CliVariant = CliExpiration; +} + +impl FromStr for CliExpiration { + type Err = String; + + fn from_str(s: &str) -> Result { + let s = s.to_lowercase(); + if s == "never" { + return Ok(Self(Expiration::Never {})); + } + let (t, num) = s.split_once(':').ok_or("Incorrect expiration format")?; + let expiration = match t { + "height" => { + let height: u64 = num.parse().map_err(|_| "Failed to parse height")?; + Expiration::AtHeight(height) + } + "time" => { + let timestamp: u64 = num.parse().map_err(|_| "Failed to parse timestamp")?; + Expiration::AtTime(Timestamp::from_nanos(timestamp)) + } + _ => return Err("Unknown expiration type".to_owned()), + }; + Ok(CliExpiration(expiration)) + } +} diff --git a/packages/cw-orch-cli/src/types/mod.rs b/packages/cw-orch-cli/src/types/mod.rs index ffce61008..02348f1da 100644 --- a/packages/cw-orch-cli/src/types/mod.rs +++ b/packages/cw-orch-cli/src/types/mod.rs @@ -1,7 +1,9 @@ mod coins; +mod expiration; mod path_buf; mod skippable; pub use coins::CliCoins; +pub use expiration::CliExpiration; pub use path_buf::PathBuf; pub use skippable::CliSkippable; From e80fdbf3a9134fc2e54bb7a2be0c12d2370f8364 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 1 Dec 2023 17:42:22 +0200 Subject: [PATCH 043/135] auto-claim if given receiver --- .../cosmwasm_tx/cw_ownable/transfer/mod.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs index ca93810ad..cd042bf3b 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use cw_orch::{ daemon::{networks::parse_network, DaemonAsync}, tokio::runtime::Runtime, @@ -69,7 +71,7 @@ impl TransferOwnershipOutput { let rt = Runtime::new()?; rt.block_on(async { - let daemon = DaemonAsync::builder() + let mut daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) .build() @@ -81,8 +83,23 @@ impl TransferOwnershipOutput { msg, funds: vec![], }; + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + if let Some(seed) = receiver_seed { + let receiver_sender = + cw_orch::daemon::sender::Sender::from_mnemonic(&daemon.state, &seed)?; + daemon.set_sender(&Rc::new(receiver_sender)); + let action = cw_ownable::Action::AcceptOwnership {}; + let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender.pub_addr()?, + contract: scope.contract_addr.parse()?, + msg, + funds: vec![], + }; + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + } color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; From b6903792cd4782b709a3246c43ec7bf1ce7e4b6b Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 1 Dec 2023 17:54:28 +0200 Subject: [PATCH 044/135] accept and renounce ownerships --- .../cosmwasm_tx/cw_ownable/accept/mod.rs | 55 +++++++++++++++++++ .../action/cosmwasm_tx/cw_ownable/mod.rs | 12 ++-- .../cosmwasm_tx/cw_ownable/renounce/mod.rs | 55 +++++++++++++++++++ .../cosmwasm_tx/cw_ownable/transfer/mod.rs | 2 +- 4 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs new file mode 100644 index 000000000..21f231352 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs @@ -0,0 +1,55 @@ +use cw_orch::{ + daemon::{networks::parse_network, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use crate::commands::action::CosmosContext; + +use super::ContractExecuteMsg; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = AcceptOwnershipOutput)] +pub struct AcceptOwnership { + /// Contract address + contract_addr: String, + /// Signer id + // TODO: should be possible to sign it from the seed phrase + signer: String, +} + +pub struct AcceptOwnershipOutput; + +impl AcceptOwnershipOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network(&previous_context.chain_id); + let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let action = cw_ownable::Action::AcceptOwnership {}; + let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; + + let rt = Runtime::new()?; + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(sender_seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender.pub_addr()?, + contract: scope.contract_addr.parse()?, + msg, + funds: vec![], + }; + + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(AcceptOwnershipOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs index 88dce2689..3ac78d509 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs @@ -3,7 +3,9 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; use crate::commands::action::CosmosContext; +mod accept; mod get; +mod renounce; mod transfer; // Helper enum to serialize execute @@ -37,12 +39,12 @@ pub enum CwOwnableAction { message = "Propose to transfer contract ownership to another address." ))] Transfer(transfer::TransferOwnership), - // /// Accept pending ownership - // #[strum_discriminants(strum(message = "Accept pending ownership."))] - // Accept(accept::AcceptOwnership), + /// Accept pending ownership + #[strum_discriminants(strum(message = "Accept pending ownership."))] + Accept(accept::AcceptOwnership), // /// Renounce pending ownership - // #[strum_discriminants(strum(message = "Renounce pending ownership"))] - // Renounce(renounce::RenounceOwnership), + #[strum_discriminants(strum(message = "Renounce pending ownership"))] + Renounce(renounce::RenounceOwnership), /// Get current ownership #[strum_discriminants(strum(message = "Get current ownership"))] Get(get::GetOwnership), diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs new file mode 100644 index 000000000..7c2ab7b10 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs @@ -0,0 +1,55 @@ +use cw_orch::{ + daemon::{networks::parse_network, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use crate::commands::action::CosmosContext; + +use super::ContractExecuteMsg; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = RenounceOwnershipOutput)] +pub struct RenounceOwnership { + /// Contract address + contract_addr: String, + /// Signer id + // TODO: should be possible to sign it from the seed phrase + signer: String, +} + +pub struct RenounceOwnershipOutput; + +impl RenounceOwnershipOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network(&previous_context.chain_id); + let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let action = cw_ownable::Action::RenounceOwnership {}; + let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; + + let rt = Runtime::new()?; + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(sender_seed) + .build() + .await?; + + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender.pub_addr()?, + contract: scope.contract_addr.parse()?, + msg, + funds: vec![], + }; + + let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(RenounceOwnershipOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs index cd042bf3b..0efd921db 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs @@ -61,7 +61,7 @@ impl TransferOwnershipOutput { .new_signer .0 .as_deref() - .map(|new_signer| crate::common::seed_phrase_for_id(new_signer)) + .map(crate::common::seed_phrase_for_id) .transpose()?; let action = cw_ownable::Action::TransferOwnership { new_owner: scope.new_owner.clone(), From fe3f0ccba8b2bcea51aeaec01862bb876f934482 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 1 Dec 2023 19:00:27 +0200 Subject: [PATCH 045/135] fix show address --- .../cw-orch-cli/src/commands/action/mod.rs | 17 +---------- .../src/commands/keys/show_address/mod.rs | 30 ++++++++++++------- packages/cw-orch-cli/src/common.rs | 20 ++++++++++++- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index e5dfea7a6..2da3d9639 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -1,8 +1,6 @@ mod cosmwasm_tx; mod transfer_tx; -use cw_orch::daemon::networks::NETWORKS; -use inquire::Select; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -31,20 +29,7 @@ pub enum CosmosAction { impl CosmosCommands { fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { - let chain_ids: Vec<_> = NETWORKS - .iter() - .map(|network| { - format!( - "{} {}({})", - network.network_info.id.to_uppercase(), - network.kind.to_string().to_uppercase(), - network.chain_id - ) - }) - .collect(); - let selected = Select::new("Select chain", chain_ids).raw_prompt()?; - let chain_id = NETWORKS[selected.index].chain_id.to_owned(); - Ok(Some(chain_id)) + crate::common::select_chain() } } diff --git a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs index eba63fff6..7d09f5031 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -1,7 +1,4 @@ -use cw_orch::{ - prelude::{networks::parse_network, Daemon, TxHandler}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::DaemonAsync, prelude::networks::parse_network, tokio::runtime::Runtime}; use crate::common::seed_phrase_for_id; @@ -11,9 +8,16 @@ use crate::common::seed_phrase_for_id; pub struct ShowAddressCommand { /// Id of the key name: String, + #[interactive_clap(skip_default_input_arg)] chain_id: String, } +impl ShowAddressCommand { + fn input_chain_id(_: &()) -> color_eyre::eyre::Result> { + crate::common::select_chain() + } +} + pub struct ShowAddressOutput; impl ShowAddressOutput { @@ -25,13 +29,17 @@ impl ShowAddressOutput { let chain = parse_network(&scope.chain_id); let rt = Runtime::new()?; - let daemon = Daemon::builder() - .handle(rt.handle()) - .chain(chain) - .mnemonic(mnemonic) - .build()?; - let address = daemon.sender(); - println!("Your address: {address}"); + // Sync daemon prints extra output, + rt.block_on(async { + let daemon = DaemonAsync::builder() + .chain(chain) + .mnemonic(mnemonic) + .build() + .await?; + let address = daemon.sender(); + println!("Your address: {address}"); + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; Ok(ShowAddressOutput) } } diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 574c83c91..a938f9fc4 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -1,6 +1,7 @@ pub use base64::prelude::BASE64_STANDARD as B64; use base64::Engine; -use inquire::{error::InquireResult, InquireError}; +use cw_orch::daemon::networks::NETWORKS; +use inquire::{error::InquireResult, InquireError, Select}; use keyring::Entry; pub fn entry_for_seed(name: &str) -> keyring::Result { @@ -18,6 +19,23 @@ pub fn get_cw_cli_exec_path() -> String { std::env::args().next().unwrap() } +pub fn select_chain() -> color_eyre::eyre::Result> { + let chain_ids: Vec<_> = NETWORKS + .iter() + .map(|network| { + format!( + "{} {}({})", + network.network_info.id.to_uppercase(), + network.kind.to_string().to_uppercase(), + network.chain_id + ) + }) + .collect(); + let selected = Select::new("Select chain", chain_ids).raw_prompt()?; + let chain_id = NETWORKS[selected.index].chain_id.to_owned(); + Ok(Some(chain_id)) +} + pub fn parse_coins() -> InquireResult { let mut coins = cosmwasm_std::Coins::default(); loop { From 265101bee5664bfd32b4b5afde3427b53730a2fe Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 1 Dec 2023 20:01:03 +0200 Subject: [PATCH 046/135] disable warning --- cw-orch-daemon/src/builder.rs | 13 ++++++++++++- cw-orch-daemon/src/sync/builder.rs | 7 +++++++ .../action/cosmwasm_tx/cw_ownable/accept/mod.rs | 1 + .../action/cosmwasm_tx/cw_ownable/renounce/mod.rs | 1 + .../action/cosmwasm_tx/cw_ownable/transfer/mod.rs | 1 + .../commands/action/cosmwasm_tx/tx/execute/mod.rs | 1 + .../action/cosmwasm_tx/tx/instantiate/mod.rs | 1 + .../src/commands/action/cosmwasm_tx/tx/store/mod.rs | 1 + .../src/commands/action/transfer_tx/cw20/mod.rs | 1 + .../src/commands/action/transfer_tx/native/mod.rs | 1 + .../src/commands/keys/show_address/mod.rs | 2 +- 11 files changed, 28 insertions(+), 2 deletions(-) diff --git a/cw-orch-daemon/src/builder.rs b/cw-orch-daemon/src/builder.rs index 258a9b98f..086691dd6 100644 --- a/cw-orch-daemon/src/builder.rs +++ b/cw-orch-daemon/src/builder.rs @@ -28,6 +28,8 @@ pub struct DaemonAsyncBuilder { pub(crate) deployment_id: Option, /// Wallet mnemonic pub(crate) mnemonic: Option, + /// Warn in case of disabled log + pub(crate) check_if_log_disabled: Option, } impl DaemonAsyncBuilder { @@ -53,6 +55,12 @@ impl DaemonAsyncBuilder { self } + /// Disables warning disabled logs output + pub fn no_warning(&mut self) -> &mut Self { + self.check_if_log_disabled = Some(false); + self + } + /// Build a daemon pub async fn build(&self) -> Result { let chain = self @@ -74,7 +82,9 @@ impl DaemonAsyncBuilder { state, sender: Rc::new(sender), }; - print_if_log_disabled(); + if self.check_if_log_disabled.unwrap_or(true) { + print_if_log_disabled(); + } Ok(daemon) } } @@ -85,6 +95,7 @@ impl From for DaemonAsyncBuilder { chain: value.chain, deployment_id: value.deployment_id, mnemonic: value.mnemonic, + check_if_log_disabled: value.check_if_log_disabled, } } } diff --git a/cw-orch-daemon/src/sync/builder.rs b/cw-orch-daemon/src/sync/builder.rs index 2f7e87486..9a34fc36b 100644 --- a/cw-orch-daemon/src/sync/builder.rs +++ b/cw-orch-daemon/src/sync/builder.rs @@ -24,6 +24,8 @@ pub struct DaemonBuilder { pub(crate) deployment_id: Option, /// Wallet mnemonic pub(crate) mnemonic: Option, + /// Warn in case of disabled log + pub(crate) check_if_log_disabled: Option, } impl DaemonBuilder { @@ -64,6 +66,11 @@ impl DaemonBuilder { self } + /// Disables warning disabled logs output + pub fn no_warning(&mut self) -> &mut Self { + self.check_if_log_disabled = Some(false); + self + } /// Build a Daemon pub fn build(&self) -> Result { let rt_handle = self diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs index 21f231352..a24968b12 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs @@ -35,6 +35,7 @@ impl AcceptOwnershipOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs index 7c2ab7b10..2c10da129 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs @@ -35,6 +35,7 @@ impl RenounceOwnershipOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs index 0efd921db..7f34159d7 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs @@ -74,6 +74,7 @@ impl TransferOwnershipOutput { let mut daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs index 69d245610..1e5c95131 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs @@ -59,6 +59,7 @@ impl ExecuteWasmOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs index dfca20f5a..77a75dbbc 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs @@ -78,6 +78,7 @@ impl InstantiateWasmOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs index 28808d8c0..69cba13ec 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs @@ -38,6 +38,7 @@ impl StoreWasmOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs index 0500d88e1..92e186c06 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs @@ -42,6 +42,7 @@ impl TransferCw20Output { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs index b5ff2947d..bbaabd706 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs @@ -47,6 +47,7 @@ impl TransferNativeOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) + .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs index 7d09f5031..3edc16a83 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -29,11 +29,11 @@ impl ShowAddressOutput { let chain = parse_network(&scope.chain_id); let rt = Runtime::new()?; - // Sync daemon prints extra output, rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(mnemonic) + .no_warning() .build() .await?; let address = daemon.sender(); From ca7602892687e659303e80f24aac09fbf3bf710d Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 4 Dec 2023 17:36:39 +0100 Subject: [PATCH 047/135] Change parse_network return type + exposed supported networks --- packages/cw-orch-networks/src/networks/mod.rs | 70 +++++++++---------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/packages/cw-orch-networks/src/networks/mod.rs b/packages/cw-orch-networks/src/networks/mod.rs index 267d5faf6..3d0c5e1cf 100644 --- a/packages/cw-orch-networks/src/networks/mod.rs +++ b/packages/cw-orch-networks/src/networks/mod.rs @@ -31,46 +31,42 @@ pub use terra::{LOCAL_TERRA, PHOENIX_1, PISCO_1}; /// ## Example /// ```rust,no_run /// use cw_orch_networks::networks::{parse_network, ChainInfo}; -/// let juno_mainnet: ChainInfo = parse_network("juno-1"); +/// let juno_mainnet: ChainInfo = parse_network("juno-1")?; /// ``` /// --- -/// supported chains are: UNI_6, JUNO_1, LOCAL_JUNO, PISCO_1, PHOENIX_1, LOCAL_TERRA, INJECTIVE_888, CONSTANTINE_1, BARYON_1, INJECTIVE_1, HARPOON_4, OSMO_4, LOCAL_OSMO -pub fn parse_network(net_id: &str) -> ChainInfo { - match parse_network_safe(net_id) { - Ok(net) => net, - Err(err) => panic!("{}", err), - } -} +/// supported chains are defined by the `SUPPORT_NETWORKS` variable -pub fn parse_network_safe(net_id: &str) -> Result { - let networks = vec![ - UNI_6, - JUNO_1, - LOCAL_JUNO, - PISCO_1, - PHOENIX_1, - LOCAL_TERRA, - INJECTIVE_888, - CONSTANTINE_3, - ARCHWAY_1, - PION_1, - NARWHAL_1, - NEUTRON_1, - INJECTIVE_1, - HARPOON_4, - OSMOSIS_1, - OSMO_5, - LOCAL_OSMO, - LOCAL_MIGALOO, - LOCAL_NEUTRON, - MIGALOO_1, - LOCAL_SEI, - SEI_DEVNET_3, - ATLANTIC_2, - PACIFIC_1, - ]; - networks - .into_iter() +pub fn parse_network(net_id: &str) -> Result { + SUPPORTED_NETWORKS + .iter() .find(|net| net.chain_id == net_id) + .cloned() .ok_or(format!("Network not found: {}", net_id)) } + +pub const SUPPORTED_NETWORKS: &[ChainInfo] = &[ + UNI_6, + JUNO_1, + LOCAL_JUNO, + PISCO_1, + PHOENIX_1, + LOCAL_TERRA, + INJECTIVE_888, + CONSTANTINE_3, + ARCHWAY_1, + PION_1, + NARWHAL_1, + NEUTRON_1, + INJECTIVE_1, + HARPOON_4, + OSMOSIS_1, + OSMO_5, + LOCAL_OSMO, + LOCAL_MIGALOO, + LOCAL_NEUTRON, + MIGALOO_1, + LOCAL_SEI, + SEI_DEVNET_3, + ATLANTIC_2, + PACIFIC_1, +]; From 6ea846470c4970e7c655ae7e82a0241c39531026 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 4 Dec 2023 17:43:14 +0100 Subject: [PATCH 048/135] Added env variable for disabling all logs --- cw-orch-daemon/src/builder.rs | 2 +- cw-orch-daemon/src/log.rs | 9 +++++++-- packages/cw-orch-core/src/env.rs | 11 +++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/cw-orch-daemon/src/builder.rs b/cw-orch-daemon/src/builder.rs index 258a9b98f..9e4910d65 100644 --- a/cw-orch-daemon/src/builder.rs +++ b/cw-orch-daemon/src/builder.rs @@ -74,7 +74,7 @@ impl DaemonAsyncBuilder { state, sender: Rc::new(sender), }; - print_if_log_disabled(); + print_if_log_disabled()?; Ok(daemon) } } diff --git a/cw-orch-daemon/src/log.rs b/cw-orch-daemon/src/log.rs index f08e0d9d1..92670261f 100644 --- a/cw-orch-daemon/src/log.rs +++ b/cw-orch-daemon/src/log.rs @@ -1,11 +1,16 @@ +use cw_orch_core::CwOrchEnvVars; + +use crate::DaemonError; + // Prints a warning if log is disabled for the application -pub fn print_if_log_disabled() { +pub fn print_if_log_disabled() -> Result<(), DaemonError> { // Here we check for logging capabilities. - if !log::log_enabled!(log::Level::Info) { + if !log::log_enabled!(log::Level::Info) && !CwOrchEnvVars::load()?.disable_logs_message { println!( "Warning: It seems like you haven't enabled logs. In order to do so, you have to : - use `env_logger::init()` at the start of your script. - Set the env variable `RUST_LOG=info` for standard logs. See https://docs.rs/env_logger/latest/env_logger/" ) } + Ok(()) } diff --git a/packages/cw-orch-core/src/env.rs b/packages/cw-orch-core/src/env.rs index ea969fe60..22dd2c6e3 100644 --- a/packages/cw-orch-core/src/env.rs +++ b/packages/cw-orch-core/src/env.rs @@ -22,6 +22,7 @@ pub const SERIALIZE_ENV_NAME: &str = "CW_ORCH_SERIALIZE_JSON"; pub const DISABLE_WALLET_BALANCE_ASSERTION_ENV_NAME: &str = "CW_ORCH_DISABLE_WALLET_BALANCE_ASSERTION"; pub const DISABLE_MANUAL_INTERACTION_ENV_NAME: &str = "CW_ORCH_DISABLE_MANUAL_INTERACTION"; +pub const DISABLE_ENABLE_LOGS_MESSAGE_ENV_NAME: &str = "CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE"; pub const MAIN_MNEMONIC_ENV_NAME: &str = "MAIN_MNEMONIC"; pub const TEST_MNEMONIC_ENV_NAME: &str = "TEST_MNEMONIC"; pub const LOCAL_MNEMONIC_ENV_NAME: &str = "LOCAL_MNEMONIC"; @@ -89,6 +90,12 @@ pub struct CwOrchEnvVars { /// Disable manual interactions /// It allows to automate scripting and get rid of prompting pub disable_manual_interaction: bool, + + /// Optional - boolean + /// Defaults to "false" + /// Disable the "Enable Logs" message + /// It allows forcing cw-orch to not output anything + pub disable_logs_message: bool, } impl Default for CwOrchEnvVars { @@ -106,6 +113,7 @@ impl Default for CwOrchEnvVars { local_mnemonic: None, disable_wallet_balance_assertion: false, disable_manual_interaction: false, + disable_logs_message: false, } } } @@ -142,6 +150,9 @@ impl CwOrchEnvVars { if let Ok(str_value) = env::var(DISABLE_MANUAL_INTERACTION_ENV_NAME) { env_values.disable_manual_interaction = str_value.parse()?; } + if let Ok(str_value) = env::var(DISABLE_ENABLE_LOGS_MESSAGE_ENV_NAME) { + env_values.disable_logs_message = str_value.parse()?; + } if let Ok(str_value) = env::var(MAIN_MNEMONIC_ENV_NAME) { env_values.main_mnemonic = Some(str_value); } From b1f4416491a5a18c16e9c4aa610275aaf1ec595e Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 4 Dec 2023 17:45:10 +0100 Subject: [PATCH 049/135] Modified docs --- docs/src/contracts/env-variable.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/contracts/env-variable.md b/docs/src/contracts/env-variable.md index 638c7c83e..ba651c06d 100644 --- a/docs/src/contracts/env-variable.md +++ b/docs/src/contracts/env-variable.md @@ -37,6 +37,8 @@ CW_ORCH_SERIALIZE_JSON = "false" # Optional - Absolute Path. Sets the directory where the state file will be saved. # This is not enforced to be an absolute path but this is highly recommended CW_ORCH_STATE_FOLDER = "~/.cw-orchestrator" +# Optional - boolean. Disable the "Enable Logs" message. +CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE = "false" ``` From f5dfd6a422d0f81865c70eaed327610ac6d4f689 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Mon, 4 Dec 2023 17:51:07 +0100 Subject: [PATCH 050/135] Added granter flag --- cw-orch-daemon/src/sender.rs | 2 +- cw-orch-daemon/src/tx_builder.rs | 19 ++++++++++++++++--- packages/cw-orch-core/src/env.rs | 9 +++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cw-orch-daemon/src/sender.rs b/cw-orch-daemon/src/sender.rs index 8c6e67e87..e7d555633 100644 --- a/cw-orch-daemon/src/sender.rs +++ b/cw-orch-daemon/src/sender.rs @@ -165,7 +165,7 @@ impl Sender { 0u8, &self.daemon_state.chain_data.fees.fee_tokens[0].denom, 0, - ); + )?; let auth_info = SignerInfo { public_key: self.private_key.get_signer_public_key(&self.secp), diff --git a/cw-orch-daemon/src/tx_builder.rs b/cw-orch-daemon/src/tx_builder.rs index b31a1eaa0..922cce18b 100644 --- a/cw-orch-daemon/src/tx_builder.rs +++ b/cw-orch-daemon/src/tx_builder.rs @@ -1,4 +1,7 @@ +use std::str::FromStr; + use cosmrs::tx::{ModeInfo, SignMode}; +use cosmrs::AccountId; use cosmrs::{ proto::cosmos::auth::v1beta1::BaseAccount, tendermint::chain::Id, @@ -6,6 +9,7 @@ use cosmrs::{ Any, Coin, }; use cw_orch_core::log::TRANSACTION_LOGS; +use cw_orch_core::CwOrchEnvVars; use secp256k1::All; use super::{sender::Sender, DaemonError}; @@ -57,9 +61,18 @@ impl TxBuilder { ) } - pub(crate) fn build_fee(amount: impl Into, denom: &str, gas_limit: u64) -> Fee { + pub(crate) fn build_fee( + amount: impl Into, + denom: &str, + gas_limit: u64, + ) -> Result { let fee = Coin::new(amount.into(), denom).unwrap(); - Fee::from_amount_and_gas(fee, gas_limit) + let mut fee = Fee::from_amount_and_gas(fee, gas_limit); + fee.granter = CwOrchEnvVars::load()? + .fee_granter + .map(|g| AccountId::from_str(&g)) + .transpose()?; + Ok(fee) } /// Builds the raw tx with a given body and fee and signs it. @@ -119,7 +132,7 @@ impl TxBuilder { (fee_amount, gas_expected) }; - let fee = Self::build_fee(tx_fee, &wallet.get_fee_token(), gas_limit); + let fee = Self::build_fee(tx_fee, &wallet.get_fee_token(), gas_limit)?; log::debug!( target: TRANSACTION_LOGS, diff --git a/packages/cw-orch-core/src/env.rs b/packages/cw-orch-core/src/env.rs index 22dd2c6e3..16be2ee18 100644 --- a/packages/cw-orch-core/src/env.rs +++ b/packages/cw-orch-core/src/env.rs @@ -23,6 +23,7 @@ pub const DISABLE_WALLET_BALANCE_ASSERTION_ENV_NAME: &str = "CW_ORCH_DISABLE_WALLET_BALANCE_ASSERTION"; pub const DISABLE_MANUAL_INTERACTION_ENV_NAME: &str = "CW_ORCH_DISABLE_MANUAL_INTERACTION"; pub const DISABLE_ENABLE_LOGS_MESSAGE_ENV_NAME: &str = "CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE"; +pub const FEE_GRANTER_ENV_NAME: &str = "CW_ORCH_FEE_GRANTER"; pub const MAIN_MNEMONIC_ENV_NAME: &str = "MAIN_MNEMONIC"; pub const TEST_MNEMONIC_ENV_NAME: &str = "TEST_MNEMONIC"; pub const LOCAL_MNEMONIC_ENV_NAME: &str = "LOCAL_MNEMONIC"; @@ -96,6 +97,10 @@ pub struct CwOrchEnvVars { /// Disable the "Enable Logs" message /// It allows forcing cw-orch to not output anything pub disable_logs_message: bool, + /// Optional - string + /// Specify a fee granter for interacting with a chain + /// This allows interacting with the blockchain and make another address pay for your fees (if allowed) + pub fee_granter: Option, } impl Default for CwOrchEnvVars { @@ -114,6 +119,7 @@ impl Default for CwOrchEnvVars { disable_wallet_balance_assertion: false, disable_manual_interaction: false, disable_logs_message: false, + fee_granter: None, } } } @@ -162,6 +168,9 @@ impl CwOrchEnvVars { if let Ok(str_value) = env::var(LOCAL_MNEMONIC_ENV_NAME) { env_values.local_mnemonic = Some(str_value); } + if let Ok(str_value) = env::var(FEE_GRANTER_ENV_NAME) { + env_values.fee_granter = Some(str_value); + } Ok(env_values) } } From 0fd7029e9d36ee3c24cb0cdc94cc9693bcdb1bbe Mon Sep 17 00:00:00 2001 From: Kayanski Date: Thu, 7 Dec 2023 12:11:06 +0100 Subject: [PATCH 051/135] Stabilized snapshots --- cw-orch/src/snapshots.rs | 7 ++++--- .../cw_orch__snapshots__tests__snapshot_test.snap | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cw-orch/src/snapshots.rs b/cw-orch/src/snapshots.rs index e0fb4ed46..d15833bf1 100644 --- a/cw-orch/src/snapshots.rs +++ b/cw-orch/src/snapshots.rs @@ -29,16 +29,17 @@ macro_rules! take_storage_snapshot { // We register and test a snapshot for all contracts storage use ::cw_orch::environment::{ChainState as _, StateInterface as _}; let all_contract_addresses = $chain.state().get_all_addresses()?; - let mut all_storage = ::std::collections::HashMap::new(); + let mut all_storage = vec![]; for (id, contract_addr) in all_contract_addresses { - all_storage.insert( + all_storage.push(( id, ::cw_orch::snapshots::parse_storage( &$chain.app.borrow().dump_wasm_raw(&contract_addr), ), - ); + )); } + all_storage.sort_by(|(id_a, _), (id_b, _)| id_a.cmp(id_b)); ::cw_orch::insta::assert_yaml_snapshot!( ::cw_orch::sanitize_filename::sanitize(format!("{}", $name)), all_storage diff --git a/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap b/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap index 34fd5e935..d0552a5aa 100644 --- a/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap +++ b/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap @@ -2,9 +2,9 @@ source: cw-orch/src/snapshots.rs expression: all_storage --- -counter_contract: - - - contract_info - - "{\"contract\":\"crates.io:counter\",\"version\":\"0.11.0\"}" - - - state - - "{\"count\":1,\"owner\":\"sender\"}" +- - counter_contract + - - - contract_info + - "{\"contract\":\"crates.io:counter\",\"version\":\"0.11.0\"}" + - - state + - "{\"count\":1,\"owner\":\"sender\"}" From e358fc5be473f87c9299668957bdd89759faf657 Mon Sep 17 00:00:00 2001 From: Kayanski Date: Thu, 7 Dec 2023 12:30:01 +0100 Subject: [PATCH 052/135] Using bTreeMap and better syntax --- cw-orch/src/snapshots.rs | 23 ++++++++++--------- ...orch__snapshots__tests__snapshot_test.snap | 10 ++++---- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/cw-orch/src/snapshots.rs b/cw-orch/src/snapshots.rs index d15833bf1..7d87999f3 100644 --- a/cw-orch/src/snapshots.rs +++ b/cw-orch/src/snapshots.rs @@ -28,18 +28,19 @@ macro_rules! take_storage_snapshot { ($chain: ident, $name: literal) => { // We register and test a snapshot for all contracts storage use ::cw_orch::environment::{ChainState as _, StateInterface as _}; - let all_contract_addresses = $chain.state().get_all_addresses()?; - let mut all_storage = vec![]; + let all_contracts = $chain.state().get_all_addresses()?; + let all_storage: ::std::collections::BTreeMap<_, _> = all_contracts + .iter() + .map(|(id, contract_addr)| { + ( + id, + ::cw_orch::snapshots::parse_storage( + &$chain.app.borrow().dump_wasm_raw(&contract_addr), + ), + ) + }) + .collect(); - for (id, contract_addr) in all_contract_addresses { - all_storage.push(( - id, - ::cw_orch::snapshots::parse_storage( - &$chain.app.borrow().dump_wasm_raw(&contract_addr), - ), - )); - } - all_storage.sort_by(|(id_a, _), (id_b, _)| id_a.cmp(id_b)); ::cw_orch::insta::assert_yaml_snapshot!( ::cw_orch::sanitize_filename::sanitize(format!("{}", $name)), all_storage diff --git a/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap b/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap index d0552a5aa..34fd5e935 100644 --- a/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap +++ b/cw-orch/src/snapshots/cw_orch__snapshots__tests__snapshot_test.snap @@ -2,9 +2,9 @@ source: cw-orch/src/snapshots.rs expression: all_storage --- -- - counter_contract - - - - contract_info - - "{\"contract\":\"crates.io:counter\",\"version\":\"0.11.0\"}" - - - state - - "{\"count\":1,\"owner\":\"sender\"}" +counter_contract: + - - contract_info + - "{\"contract\":\"crates.io:counter\",\"version\":\"0.11.0\"}" + - - state + - "{\"count\":1,\"owner\":\"sender\"}" From f76d61c3eddedcd6d56dc4de61eda503e9d2a2a8 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 12:11:58 +0200 Subject: [PATCH 053/135] disable logs message --- .../commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs | 3 +-- .../src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs | 2 +- .../action/cosmwasm_tx/cw_ownable/renounce/mod.rs | 3 +-- .../action/cosmwasm_tx/cw_ownable/transfer/mod.rs | 3 +-- .../action/cosmwasm_tx/query/query_contract_smart/mod.rs | 2 +- .../src/commands/action/cosmwasm_tx/tx/execute/mod.rs | 8 ++------ .../src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs | 3 +-- .../src/commands/action/cosmwasm_tx/tx/store/mod.rs | 3 +-- .../src/commands/action/transfer_tx/cw20/mod.rs | 6 ++---- .../src/commands/action/transfer_tx/native/mod.rs | 6 ++---- .../cw-orch-cli/src/commands/keys/show_address/mod.rs | 3 +-- packages/cw-orch-cli/src/common.rs | 2 +- packages/cw-orch-cli/src/daemon/mod.rs | 3 ++- packages/cw-orch-cli/src/main.rs | 1 + 14 files changed, 18 insertions(+), 30 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs index a24968b12..736f5223e 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs @@ -25,7 +25,7 @@ impl AcceptOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; @@ -35,7 +35,6 @@ impl AcceptOwnershipOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs index 144069132..73ecc4eee 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs @@ -26,7 +26,7 @@ impl GetOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; let chain_data: ChainRegistryData = chain.into(); diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs index 2c10da129..0ae56739f 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs @@ -25,7 +25,7 @@ impl RenounceOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::RenounceOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; @@ -35,7 +35,6 @@ impl RenounceOwnershipOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs index 7f34159d7..dc83dea14 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs @@ -55,7 +55,7 @@ impl TransferOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let receiver_seed = scope .new_signer @@ -74,7 +74,6 @@ impl TransferOwnershipOutput { let mut daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs index cc9aee198..2a5dac6b2 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs @@ -40,7 +40,7 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; let chain_data: ChainRegistryData = chain.into(); diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs index 1e5c95131..1b5bbd889 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs @@ -1,7 +1,5 @@ use color_eyre::eyre::{self, Context}; -use cw_orch::{ - daemon::networks::parse_network_safe, prelude::DaemonAsync, tokio::runtime::Runtime, -}; +use cw_orch::{daemon::networks::parse_network, prelude::DaemonAsync, tokio::runtime::Runtime}; use crate::{commands::action::CosmosContext, types::CliCoins}; @@ -48,8 +46,7 @@ impl ExecuteWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = - parse_network_safe(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let chain = parse_network(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; @@ -59,7 +56,6 @@ impl ExecuteWasmOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs index 77a75dbbc..4eda3d3a4 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs @@ -68,7 +68,7 @@ impl InstantiateWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; @@ -78,7 +78,6 @@ impl InstantiateWasmOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs index 69cba13ec..4fed7b116 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs @@ -26,7 +26,7 @@ impl StoreWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id); + let chain = parse_network(&previous_context.chain_id).unwrap(); let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let wasm_byte_code = std::fs::read(&scope.wasm_path).wrap_err(format!( "Failed to open or read the file: {}", @@ -38,7 +38,6 @@ impl StoreWasmOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs index 92e186c06..86714ca5e 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs @@ -1,7 +1,7 @@ use color_eyre::eyre; use cosmwasm_std::Uint128; use cw_orch::{ - daemon::{networks::parse_network_safe, DaemonAsync}, + daemon::{networks::parse_network, DaemonAsync}, tokio::runtime::Runtime, }; @@ -28,8 +28,7 @@ impl TransferCw20Output { previous_context: CosmosContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = - parse_network_safe(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let chain = parse_network(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { recipient: scope.to_address.clone(), @@ -42,7 +41,6 @@ impl TransferCw20Output { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs index bbaabd706..dd5ca4ad1 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::{self, Context}; use cw_orch::{ - daemon::{networks::parse_network_safe, DaemonAsync}, + daemon::{networks::parse_network, DaemonAsync}, tokio::runtime::Runtime, }; @@ -36,8 +36,7 @@ impl TransferNativeOutput { previous_context: CosmosContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = - parse_network_safe(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let chain = parse_network(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins: Vec = (&scope.coins).try_into()?; @@ -47,7 +46,6 @@ impl TransferNativeOutput { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) - .no_warning() .build() .await?; diff --git a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs index 3edc16a83..9834a1093 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -26,14 +26,13 @@ impl ShowAddressOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let mnemonic = seed_phrase_for_id(&scope.name)?; - let chain = parse_network(&scope.chain_id); + let chain = parse_network(&scope.chain_id).unwrap(); let rt = Runtime::new()?; rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(mnemonic) - .no_warning() .build() .await?; let address = daemon.sender(); diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index a938f9fc4..0da3f6e52 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -1,6 +1,6 @@ pub use base64::prelude::BASE64_STANDARD as B64; use base64::Engine; -use cw_orch::daemon::networks::NETWORKS; +use cw_orch::daemon::networks::SUPPORTED_NETWORKS as NETWORKS; use inquire::{error::InquireResult, InquireError, Select}; use keyring::Entry; diff --git a/packages/cw-orch-cli/src/daemon/mod.rs b/packages/cw-orch-cli/src/daemon/mod.rs index 2f12886e7..326be49a3 100644 --- a/packages/cw-orch-cli/src/daemon/mod.rs +++ b/packages/cw-orch-cli/src/daemon/mod.rs @@ -1,4 +1,5 @@ use cw_orch::{ + anyhow::anyhow, prelude::{networks::parse_network, Daemon, DaemonBuilder}, tokio::runtime::Handle, }; @@ -8,7 +9,7 @@ pub trait DaemonFromCli { let network_str = inquire::Text::new("Chain id") .with_placeholder("uni-6") .prompt()?; - let network = parse_network(&network_str); + let network = parse_network(&network_str).map_err(|e| anyhow!(e))?; let chain = DaemonBuilder::default() .handle(handle) .chain(network) diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index cf9550fc4..f0775e41f 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -10,6 +10,7 @@ pub struct TLCommand { } fn main() -> color_eyre::Result<()> { + std::env::set_var("CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE", "true"); // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); From 72fd346c1aa43d39cdf1bbe197dba0bf4a511b06 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 12:17:51 +0200 Subject: [PATCH 054/135] add comment on disabling log messages --- packages/cw-orch-cli/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index f0775e41f..dba64f23f 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -10,6 +10,7 @@ pub struct TLCommand { } fn main() -> color_eyre::Result<()> { + // We don't want to see logs in stdout during cli std::env::set_var("CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE", "true"); // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); From afe47b6f307a2d7ccdb0fff71a2942571975a713 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 16:04:46 +0200 Subject: [PATCH 055/135] fix macos keyring --- packages/cw-orch-cli/src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 0da3f6e52..08a2ac3c0 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -5,7 +5,7 @@ use inquire::{error::InquireResult, InquireError, Select}; use keyring::Entry; pub fn entry_for_seed(name: &str) -> keyring::Result { - Entry::new_with_target("cw-orch", "cw-cli", name) + Entry::new("cw-cli", name) } pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { From 0a1921217ddc26f0a713d784c09395a8004a95f9 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 16:35:16 +0200 Subject: [PATCH 056/135] fix coin parse --- packages/cw-orch-cli/src/common.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 08a2ac3c0..0025e1a83 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -39,18 +39,24 @@ pub fn select_chain() -> color_eyre::eyre::Result> { pub fn parse_coins() -> InquireResult { let mut coins = cosmwasm_std::Coins::default(); loop { - let coin = inquire::CustomType::::new("Add coin to transaction") - .with_placeholder("5ucosm") + let coin = inquire::Text::new("Add coin to transaction") + .with_placeholder("0ucoin") .with_help_message("Press ESC to finish adding coins") - .prompt_skippable()?; - if let Some(c) = coin { - coins - .add(c) - .map_err(|e| InquireError::Custom(Box::new(e)))? + .prompt()?; + if !coin.is_empty() { + match coin.parse() { + Ok(c) => coins + .add(c) + .map_err(|e| InquireError::Custom(Box::new(e)))?, + Err(e) => { + println!("Failed to add coin: {e}") + } + } } else { break; } } + println!("attached coins: {coins}"); Ok(coins) } From 9b79c40d44b4eca0e1c734f1e0ae6cfb5cb1bc9a Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 16:35:31 +0200 Subject: [PATCH 057/135] rename cw-ownable action --- packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs index 2bf0e8092..7fe24c69f 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs @@ -25,7 +25,7 @@ pub enum CwAction { /// Query #[strum_discriminants(strum(message = "Query"))] Query(query::QueryCommands), - /// CW-Ownable Action - #[strum_discriminants(strum(message = "CW-Ownable action"))] + /// CW-Ownable + #[strum_discriminants(strum(message = "CW-Ownable"))] CwOwnable(cw_ownable::CwOwnableCommands), } From bdd429e8f6ced6dcf80bed7d47d107ffc7097cf4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 16:38:11 +0200 Subject: [PATCH 058/135] move cw-ownable --- packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs | 4 ---- .../action/{cosmwasm_tx => }/cw_ownable/accept/mod.rs | 0 .../commands/action/{cosmwasm_tx => }/cw_ownable/get/mod.rs | 0 .../src/commands/action/{cosmwasm_tx => }/cw_ownable/mod.rs | 0 .../action/{cosmwasm_tx => }/cw_ownable/renounce/mod.rs | 0 .../action/{cosmwasm_tx => }/cw_ownable/transfer/mod.rs | 0 packages/cw-orch-cli/src/commands/action/mod.rs | 4 ++++ 7 files changed, 4 insertions(+), 4 deletions(-) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => }/cw_ownable/accept/mod.rs (100%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => }/cw_ownable/get/mod.rs (100%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => }/cw_ownable/mod.rs (100%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => }/cw_ownable/renounce/mod.rs (100%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => }/cw_ownable/transfer/mod.rs (100%) diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs index 7fe24c69f..cdb7b47e8 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs @@ -1,4 +1,3 @@ -mod cw_ownable; pub mod msg_type; mod query; mod tx; @@ -25,7 +24,4 @@ pub enum CwAction { /// Query #[strum_discriminants(strum(message = "Query"))] Query(query::QueryCommands), - /// CW-Ownable - #[strum_discriminants(strum(message = "CW-Ownable"))] - CwOwnable(cw_ownable::CwOwnableCommands), } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/accept/mod.rs rename to packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/get/mod.rs rename to packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/mod.rs rename to packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/renounce/mod.rs rename to packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/cw_ownable/transfer/mod.rs rename to packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index 2da3d9639..b04dff556 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -1,4 +1,5 @@ mod cosmwasm_tx; +mod cw_ownable; mod transfer_tx; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; @@ -25,6 +26,9 @@ pub enum CosmosAction { // /// Transfer Action #[strum_discriminants(strum(message = "Perform Transfer action"))] Transfer(transfer_tx::TransferCommands), + /// CW-Ownable + #[strum_discriminants(strum(message = "CW-Ownable"))] + CwOwnable(cw_ownable::CwOwnableCommands), } impl CosmosCommands { From eedad7c9e88c458d3ac94494b7fe1f351cbf209c Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 16:42:06 +0200 Subject: [PATCH 059/135] messages update --- packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs | 4 +--- packages/cw-orch-cli/src/commands/action/mod.rs | 7 ++++--- packages/cw-orch-cli/src/commands/mod.rs | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs index 3ac78d509..a33cb8557 100644 --- a/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs @@ -35,9 +35,7 @@ pub struct CwOwnableCommands { /// Select cosmwasm action pub enum CwOwnableAction { /// Propose to transfer contract ownership to another address - #[strum_discriminants(strum( - message = "Propose to transfer contract ownership to another address." - ))] + #[strum_discriminants(strum(message = "Propose ownership to another address."))] Transfer(transfer::TransferOwnership), /// Accept pending ownership #[strum_discriminants(strum(message = "Accept pending ownership."))] diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index b04dff556..ecc137b31 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -21,12 +21,13 @@ pub struct CosmosCommands { /// Select type of cosmos action pub enum CosmosAction { /// Cosmwasm Action - #[strum_discriminants(strum(message = "Perform CosmWasm action"))] + #[strum_discriminants(strum(message = "CosmWasm"))] Cw(cosmwasm_tx::CwCommands), + // TODO: rename and expand to bank? // /// Transfer Action - #[strum_discriminants(strum(message = "Perform Transfer action"))] + #[strum_discriminants(strum(message = "Transfer"))] Transfer(transfer_tx::TransferCommands), - /// CW-Ownable + /// CW-Ownable Action #[strum_discriminants(strum(message = "CW-Ownable"))] CwOwnable(cw_ownable::CwOwnableCommands), } diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index e207bc8e4..d48c42ab6 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -7,8 +7,8 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[strum_discriminants(derive(EnumMessage, EnumIter))] /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { - /// Construct action - #[strum_discriminants(strum(message = "Construct action"))] + /// Action + #[strum_discriminants(strum(message = "Action"))] Action(action::CosmosCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "Manage keys"))] From 4666f45c15cfe10b6a0daf3e0f1502b64396f7f2 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 8 Dec 2023 16:50:02 +0200 Subject: [PATCH 060/135] raw query --- .../commands/action/cosmwasm_tx/query/mod.rs | 10 ++-- .../action/cosmwasm_tx/query/raw/mod.rs | 52 +++++++++++++++++++ .../{query_contract_smart => smart}/mod.rs | 2 - 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs rename packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/{query_contract_smart => smart}/mod.rs (95%) diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs index 2685c2f8f..c24d1dc6b 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs @@ -2,7 +2,8 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; use crate::commands::action::CosmosContext; -mod query_contract_smart; +mod raw; +mod smart; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(context = CosmosContext)] @@ -17,6 +18,9 @@ pub struct QueryCommands { /// Select cosmwasm action pub enum QueryAction { /// Query wasm smart - #[strum_discriminants(strum(message = "Query wasm smart"))] - Smart(query_contract_smart::QuerySmartCommands), + #[strum_discriminants(strum(message = "Smart"))] + Smart(smart::QuerySmartCommands), + /// Query wasm raw state + #[strum_discriminants(strum(message = "Raw"))] + Raw(raw::QueryRawCommands), } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs new file mode 100644 index 000000000..477503931 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs @@ -0,0 +1,52 @@ +use cosmrs::proto::cosmwasm::wasm::v1::{query_client::QueryClient, QueryRawContractStateRequest}; +use cw_orch::{ + daemon::{ChainRegistryData, GrpcChannel}, + prelude::networks::parse_network, + tokio::runtime::Runtime, +}; + +use crate::commands::action::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = QueryWasmOutput)] +pub struct QueryRawCommands { + /// Contract address + contract_addr: String, + // TODO: add base-64 option for binary keys + /// Enter key + key: String, +} + +pub struct QueryWasmOutput; + +impl QueryWasmOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = parse_network(&previous_context.chain_id).unwrap(); + + let chain_data: ChainRegistryData = chain.into(); + + let rt = Runtime::new()?; + rt.block_on(async { + let grpc_channel = + GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + let mut client = QueryClient::new(grpc_channel); + + let resp = client + .raw_contract_state(QueryRawContractStateRequest { + address: scope.contract_addr.clone(), + query_data: scope.key.clone().into_bytes(), + }) + .await?; + + let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(QueryWasmOutput) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs similarity index 95% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs index 2a5dac6b2..38af8c047 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/query_contract_smart/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs @@ -51,8 +51,6 @@ impl QueryWasmOutput { GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; let mut client = QueryClient::new(grpc_channel); - // TODO: support other types of queries - // It should be possible to support `Any` on query let resp = client .smart_contract_state(QuerySmartContractStateRequest { address: scope.contract_addr.clone(), From 749856e09df20aebd2a98a7d71f0b21d9b2da34d Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 18 Dec 2023 16:08:24 +0200 Subject: [PATCH 061/135] Save chain instead of chain-id after locking --- .../action/cosmwasm_tx/query/raw/mod.rs | 3 +- .../action/cosmwasm_tx/query/smart/mod.rs | 4 +- .../action/cosmwasm_tx/tx/execute/mod.rs | 6 +-- .../action/cosmwasm_tx/tx/instantiate/mod.rs | 5 +-- .../action/cosmwasm_tx/tx/store/mod.rs | 5 +-- .../commands/action/cw_ownable/accept/mod.rs | 7 +--- .../src/commands/action/cw_ownable/get/mod.rs | 6 +-- .../action/cw_ownable/renounce/mod.rs | 7 +--- .../action/cw_ownable/transfer/mod.rs | 7 +--- .../cw-orch-cli/src/commands/action/mod.rs | 10 +++-- .../commands/action/transfer_tx/cw20/mod.rs | 8 +--- .../commands/action/transfer_tx/native/mod.rs | 9 ++-- .../src/commands/keys/show_address/mod.rs | 10 ++--- packages/cw-orch-cli/src/common.rs | 7 ++-- packages/cw-orch-cli/src/lib.rs | 1 + packages/cw-orch-cli/src/main.rs | 2 +- packages/cw-orch-cli/src/types/chain.rs | 41 +++++++++++++++++++ packages/cw-orch-cli/src/types/mod.rs | 2 + 18 files changed, 82 insertions(+), 58 deletions(-) create mode 100644 packages/cw-orch-cli/src/types/chain.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs index 477503931..5adb70594 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs @@ -1,7 +1,6 @@ use cosmrs::proto::cosmwasm::wasm::v1::{query_client::QueryClient, QueryRawContractStateRequest}; use cw_orch::{ daemon::{ChainRegistryData, GrpcChannel}, - prelude::networks::parse_network, tokio::runtime::Runtime, }; @@ -25,7 +24,7 @@ impl QueryWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let chain_data: ChainRegistryData = chain.into(); diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs index 38af8c047..a401723e1 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs @@ -3,7 +3,6 @@ use cosmrs::proto::cosmwasm::wasm::v1::{ }; use cw_orch::{ daemon::{ChainRegistryData, GrpcChannel}, - prelude::networks::parse_network, tokio::runtime::Runtime, }; @@ -39,8 +38,7 @@ impl QueryWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; let chain_data: ChainRegistryData = chain.into(); diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs index 1b5bbd889..9b1670f8e 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs @@ -1,5 +1,5 @@ -use color_eyre::eyre::{self, Context}; -use cw_orch::{daemon::networks::parse_network, prelude::DaemonAsync, tokio::runtime::Runtime}; +use color_eyre::eyre::Context; +use cw_orch::{prelude::DaemonAsync, tokio::runtime::Runtime}; use crate::{commands::action::CosmosContext, types::CliCoins}; @@ -46,7 +46,7 @@ impl ExecuteWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let chain = previous_context.chain; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs index 4eda3d3a4..0e298b42f 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Context; use cw_orch::{ - prelude::{networks::parse_network, DaemonAsync, IndexResponse}, + prelude::{DaemonAsync, IndexResponse}, tokio::runtime::Runtime, }; @@ -67,8 +67,7 @@ impl InstantiateWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs index 4fed7b116..4ca7b57c5 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Context; use cw_orch::{ - prelude::{networks::parse_network, DaemonAsync, IndexResponse}, + prelude::{DaemonAsync, IndexResponse}, tokio::runtime::Runtime, }; @@ -25,8 +25,7 @@ impl StoreWasmOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - // TODO: non-panic parse_network - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let wasm_byte_code = std::fs::read(&scope.wasm_path).wrap_err(format!( "Failed to open or read the file: {}", diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 736f5223e..5d3635bb7 100644 --- a/packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,7 +1,4 @@ -use cw_orch::{ - daemon::{networks::parse_network, DaemonAsync}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; use crate::commands::action::CosmosContext; @@ -25,7 +22,7 @@ impl AcceptOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index 73ecc4eee..f4eab66d2 100644 --- a/packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -1,5 +1,5 @@ use cw_orch::{ - daemon::{networks::parse_network, ChainRegistryData, GrpcChannel}, + daemon::{ChainRegistryData, GrpcChannel}, tokio::runtime::Runtime, }; @@ -26,7 +26,7 @@ impl GetOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; let chain_data: ChainRegistryData = chain.into(); @@ -36,8 +36,6 @@ impl GetOwnershipOutput { GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; let mut client = QueryClient::new(grpc_channel); - // TODO: support other types of queries - // It should be possible to support `Any` on query let resp = client .smart_contract_state(QuerySmartContractStateRequest { address: scope.contract_addr.clone(), diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index 0ae56739f..a213b7b3b 100644 --- a/packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -1,7 +1,4 @@ -use cw_orch::{ - daemon::{networks::parse_network, DaemonAsync}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; use crate::commands::action::CosmosContext; @@ -25,7 +22,7 @@ impl RenounceOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::RenounceOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index dc83dea14..0d8db334d 100644 --- a/packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -1,9 +1,6 @@ use std::rc::Rc; -use cw_orch::{ - daemon::{networks::parse_network, DaemonAsync}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; use crate::{ commands::action::CosmosContext, @@ -55,7 +52,7 @@ impl TransferOwnershipOutput { previous_context: CosmosContext, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).unwrap(); + let chain = previous_context.chain; let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let receiver_seed = scope .new_signer diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index ecc137b31..6bf8ae9ee 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -4,13 +4,15 @@ mod transfer_tx; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; +use crate::types::CliLockedChain; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = CosmosContext)] pub struct CosmosCommands { #[interactive_clap(skip_default_input_arg)] /// Chain id - chain_id: String, + chain_id: CliLockedChain, #[interactive_clap(subcommand)] action: CosmosAction, } @@ -33,7 +35,7 @@ pub enum CosmosAction { } impl CosmosCommands { - fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { + fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { crate::common::select_chain() } } @@ -44,7 +46,7 @@ impl From for () { #[derive(Clone)] pub struct CosmosContext { - chain_id: String, + chain: CliLockedChain, } impl CosmosContext { @@ -53,7 +55,7 @@ impl CosmosContext { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { Ok(CosmosContext { - chain_id: scope.chain_id.clone(), + chain: scope.chain_id, }) } } diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs index 86714ca5e..f04b50d9a 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs @@ -1,9 +1,5 @@ -use color_eyre::eyre; use cosmwasm_std::Uint128; -use cw_orch::{ - daemon::{networks::parse_network, DaemonAsync}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; use super::CosmosContext; @@ -28,7 +24,7 @@ impl TransferCw20Output { previous_context: CosmosContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let chain = previous_context.chain; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { recipient: scope.to_address.clone(), diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs index dd5ca4ad1..02fd236a7 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs @@ -1,8 +1,5 @@ -use color_eyre::eyre::{self, Context}; -use cw_orch::{ - daemon::{networks::parse_network, DaemonAsync}, - tokio::runtime::Runtime, -}; +use color_eyre::eyre::Context; +use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; use crate::types::CliCoins; @@ -36,7 +33,7 @@ impl TransferNativeOutput { previous_context: CosmosContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = parse_network(&previous_context.chain_id).map_err(|err| eyre::eyre!(err))?; + let chain = previous_context.chain; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins: Vec = (&scope.coins).try_into()?; diff --git a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs index 9834a1093..e720bb187 100644 --- a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -1,6 +1,6 @@ -use cw_orch::{daemon::DaemonAsync, prelude::networks::parse_network, tokio::runtime::Runtime}; +use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::common::seed_phrase_for_id; +use crate::{common::seed_phrase_for_id, types::CliLockedChain}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] @@ -9,11 +9,11 @@ pub struct ShowAddressCommand { /// Id of the key name: String, #[interactive_clap(skip_default_input_arg)] - chain_id: String, + chain_id: CliLockedChain, } impl ShowAddressCommand { - fn input_chain_id(_: &()) -> color_eyre::eyre::Result> { + fn input_chain_id(_: &()) -> color_eyre::eyre::Result> { crate::common::select_chain() } } @@ -26,7 +26,7 @@ impl ShowAddressOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let mnemonic = seed_phrase_for_id(&scope.name)?; - let chain = parse_network(&scope.chain_id).unwrap(); + let chain = scope.chain_id; let rt = Runtime::new()?; rt.block_on(async { diff --git a/packages/cw-orch-cli/src/common.rs b/packages/cw-orch-cli/src/common.rs index 0025e1a83..668678938 100644 --- a/packages/cw-orch-cli/src/common.rs +++ b/packages/cw-orch-cli/src/common.rs @@ -1,3 +1,4 @@ +use crate::types::CliLockedChain; pub use base64::prelude::BASE64_STANDARD as B64; use base64::Engine; use cw_orch::daemon::networks::SUPPORTED_NETWORKS as NETWORKS; @@ -19,7 +20,7 @@ pub fn get_cw_cli_exec_path() -> String { std::env::args().next().unwrap() } -pub fn select_chain() -> color_eyre::eyre::Result> { +pub fn select_chain() -> color_eyre::eyre::Result> { let chain_ids: Vec<_> = NETWORKS .iter() .map(|network| { @@ -32,8 +33,8 @@ pub fn select_chain() -> color_eyre::eyre::Result> { }) .collect(); let selected = Select::new("Select chain", chain_ids).raw_prompt()?; - let chain_id = NETWORKS[selected.index].chain_id.to_owned(); - Ok(Some(chain_id)) + let locked_chain = CliLockedChain::new(selected.index); + Ok(Some(locked_chain)) } pub fn parse_coins() -> InquireResult { diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index bc401aa5b..91ea91293 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,5 +1,6 @@ /// Allow integrating keys and stuff pub mod common; +pub mod types; mod contract; mod daemon; diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index dba64f23f..5c7df304b 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,6 +1,6 @@ mod commands; mod common; -mod types; +pub(crate) mod types; use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] diff --git a/packages/cw-orch-cli/src/types/chain.rs b/packages/cw-orch-cli/src/types/chain.rs new file mode 100644 index 000000000..6ab0ab6f2 --- /dev/null +++ b/packages/cw-orch-cli/src/types/chain.rs @@ -0,0 +1,41 @@ +use std::str::FromStr; + +use cw_orch::daemon::{networks::SUPPORTED_NETWORKS, ChainRegistryData}; + +#[derive(Default, Debug, Clone, Copy)] +pub struct CliLockedChain(usize); + +impl CliLockedChain { + pub fn new(index: usize) -> Self { + CliLockedChain(index) + } +} + +impl From for ChainRegistryData { + fn from(value: CliLockedChain) -> Self { + SUPPORTED_NETWORKS[value.0].to_owned().into() + } +} + +impl FromStr for CliLockedChain { + type Err = String; + + // Just parse chain id + fn from_str(s: &str) -> Result { + SUPPORTED_NETWORKS + .iter() + .position(|c| c.chain_id == s) + .map(CliLockedChain::new) + .ok_or("Unknown network".to_owned()) + } +} + +impl ToString for CliLockedChain { + fn to_string(&self) -> String { + SUPPORTED_NETWORKS[self.0].chain_id.to_owned() + } +} + +impl interactive_clap::ToCli for CliLockedChain { + type CliVariant = CliLockedChain; +} diff --git a/packages/cw-orch-cli/src/types/mod.rs b/packages/cw-orch-cli/src/types/mod.rs index 02348f1da..5eefffea9 100644 --- a/packages/cw-orch-cli/src/types/mod.rs +++ b/packages/cw-orch-cli/src/types/mod.rs @@ -1,8 +1,10 @@ +mod chain; mod coins; mod expiration; mod path_buf; mod skippable; +pub use chain::CliLockedChain; pub use coins::CliCoins; pub use expiration::CliExpiration; pub use path_buf::PathBuf; From 2d41da65a36e46c16db84aab2d3acd5bb9d324d4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 21 Dec 2023 18:08:32 +0200 Subject: [PATCH 062/135] add latest command to the history --- packages/cw-orch-cli/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/cw-orch-cli/README.md b/packages/cw-orch-cli/README.md index 2801217fa..117f83b4a 100644 --- a/packages/cw-orch-cli/README.md +++ b/packages/cw-orch-cli/README.md @@ -1,3 +1,12 @@ ## Cw Orch CLI Cw Orch CLI is a command line utility for working with cosmos blockhains + +## Add latest command to the history +You can add this function to ~/.bashrc to append the last executed command to the current session history: +```bash +cw-orch-cli() { + command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2 -d':') + history -s $command +} +``` \ No newline at end of file From 713771ec1111b64e3faac6195c7980ddf226dd4e Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 13:43:11 +0200 Subject: [PATCH 063/135] fix cosmrs update --- packages/cw-orch-cli/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index f47c38a9f..b03f1b74b 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true thiserror = { workspace = true } directories = "5.0.1" keyring = "2.0.5" -cosmrs = "0.14.0" +cosmrs = { version = "0.15.0", features = ["cosmwasm"] } rand_core = { version = "0.6", features = ["std"] } base64 = { version = "0.21.0" } # TODO: move to workspace cosmwasm-std = { version = "1.3" } @@ -26,7 +26,7 @@ clap = { version = "4.0.18", features = ["derive"] } color-eyre = { version = "0.6" } inquire = { version = "0.6" } strum = { version = "0.24", features = ["derive"] } - +bip32 = { version = "0.5", features = ["mnemonic"] } dotenv = { version = "0.15.0" } serde_json = "1.0.79" From a4f065c4d7767269034a56c0d31635e2feab3ab5 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 21:05:21 +0200 Subject: [PATCH 064/135] ux improvement and balance queries --- packages/cw-orch-cli/Cargo.toml | 2 +- .../src/commands/action/asset/mod.rs | 35 +++++++ .../commands/action/asset/query_cw20/mod.rs | 57 ++++++++++++ .../commands/action/asset/query_native/mod.rs | 92 +++++++++++++++++++ .../cw20 => asset/send_cw20}/mod.rs | 23 +++-- .../native => asset/send_native}/mod.rs | 29 +++--- .../tx => cosmwasm}/execute/mod.rs | 13 ++- .../tx => cosmwasm}/instantiate/mod.rs | 20 ++-- .../{cosmwasm_tx/tx => cosmwasm}/mod.rs | 25 +++-- .../{cosmwasm_tx => cosmwasm}/msg_type/mod.rs | 0 .../{cosmwasm_tx => cosmwasm}/query/mod.rs | 4 +- .../query/raw/mod.rs | 15 ++- .../query/smart/mod.rs | 12 ++- .../{cosmwasm_tx/tx => cosmwasm}/store/mod.rs | 21 ++--- .../src/commands/action/cosmwasm_tx/mod.rs | 27 ------ .../src/commands/action/cw_ownable/mod.rs | 8 +- .../cw-orch-cli/src/commands/action/mod.rs | 19 ++-- .../src/commands/action/transfer_tx/mod.rs | 27 ------ packages/cw-orch-cli/src/commands/keys/mod.rs | 8 +- packages/cw-orch-cli/src/commands/mod.rs | 9 +- packages/cw-orch-cli/src/log/mod.rs | 11 +++ packages/cw-orch-cli/src/main.rs | 3 +- 22 files changed, 314 insertions(+), 146 deletions(-) create mode 100644 packages/cw-orch-cli/src/commands/action/asset/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs create mode 100644 packages/cw-orch-cli/src/commands/action/asset/query_native/mod.rs rename packages/cw-orch-cli/src/commands/action/{transfer_tx/cw20 => asset/send_cw20}/mod.rs (75%) rename packages/cw-orch-cli/src/commands/action/{transfer_tx/native => asset/send_native}/mod.rs (66%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx/tx => cosmwasm}/execute/mod.rs (86%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx/tx => cosmwasm}/instantiate/mod.rs (86%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx/tx => cosmwasm}/mod.rs (60%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => cosmwasm}/msg_type/mod.rs (100%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => cosmwasm}/query/mod.rs (85%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => cosmwasm}/query/raw/mod.rs (74%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx => cosmwasm}/query/smart/mod.rs (81%) rename packages/cw-orch-cli/src/commands/action/{cosmwasm_tx/tx => cosmwasm}/store/mod.rs (78%) delete mode 100644 packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs delete mode 100644 packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs create mode 100644 packages/cw-orch-cli/src/log/mod.rs diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index b03f1b74b..99adce3d3 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true thiserror = { workspace = true } directories = "5.0.1" keyring = "2.0.5" -cosmrs = { version = "0.15.0", features = ["cosmwasm"] } +cosmrs = { version = "0.15.0", features = ["cosmwasm", "grpc"] } rand_core = { version = "0.6", features = ["std"] } base64 = { version = "0.21.0" } # TODO: move to workspace cosmwasm-std = { version = "1.3" } diff --git a/packages/cw-orch-cli/src/commands/action/asset/mod.rs b/packages/cw-orch-cli/src/commands/action/asset/mod.rs new file mode 100644 index 000000000..6cac98067 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/asset/mod.rs @@ -0,0 +1,35 @@ +mod query_cw20; +mod query_native; +mod send_cw20; +mod send_native; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +use super::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(context = CosmosContext)] +pub struct AssetCommands { + #[interactive_clap(subcommand)] + action: AssetAction, +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = CosmosContext)] +/// Select asset action +pub enum AssetAction { + /// Native or factory coin send + #[strum_discriminants(strum(message = "Send native coins"))] + SendNative(send_native::SendNativeCommands), + /// Native or factory coin transfer + #[strum_discriminants(strum(message = "Send cw20 coin"))] + SendCw20(send_cw20::Cw20TransferCommands), + /// Native or factory coins query + #[strum_discriminants(strum(message = "Query native coins"))] + QueryNative(query_native::QueryNativeCommands), + /// Cw20 coin query + #[strum_discriminants(strum(message = "Query cw20 coins"))] + QueryCw20(query_cw20::QueryCw20Commands), + // TODO: cw720? +} diff --git a/packages/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/packages/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs new file mode 100644 index 000000000..d1fb85d11 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -0,0 +1,57 @@ +use cw20::BalanceResponse; +use cw_orch::{ + daemon::{ChainRegistryData, GrpcChannel}, + tokio::runtime::Runtime, +}; + +use cosmrs::proto::cosmwasm::wasm::v1::{ + query_client::QueryClient, QuerySmartContractStateRequest, +}; + +use super::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = QueryCw20Output)] +pub struct QueryCw20Commands { + /// Input cw20 address + cw20_address: String, + /// Address + address: String, +} + +pub struct QueryCw20Output; + +impl QueryCw20Output { + fn from_previous_context( + previous_context: CosmosContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + let chain_data: ChainRegistryData = chain.into(); + let msg = serde_json::to_vec(&cw20::Cw20QueryMsg::Balance { + address: scope.address.clone(), + })?; + + let rt = Runtime::new()?; + + rt.block_on(async { + let grpc_channel = + GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + let mut client = QueryClient::new(grpc_channel); + + let resp = client + .smart_contract_state(QuerySmartContractStateRequest { + address: scope.cw20_address.clone(), + query_data: msg, + }) + .await?; + let parsed_output: BalanceResponse = serde_json::from_slice(&resp.into_inner().data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(QueryCw20Output) + } +} diff --git a/packages/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/packages/cw-orch-cli/src/commands/action/asset/query_native/mod.rs new file mode 100644 index 000000000..40c0a9eb0 --- /dev/null +++ b/packages/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -0,0 +1,92 @@ +use cosmrs::proto::cosmos::{ + bank::v1beta1::{ + query_client::QueryClient, QueryAllBalancesRequest, QueryAllBalancesResponse, + QueryBalanceRequest, QueryBalanceResponse, + }, + base::v1beta1::Coin, +}; +use cw_orch::{ + daemon::{ChainRegistryData, GrpcChannel}, + tokio::runtime::Runtime, +}; + +use crate::types::CliSkippable; + +use super::CosmosContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = QueryNativeOutput)] +pub struct QueryNativeCommands { + /// Input denom or leave empty to query all balances + denom: CliSkippable, + /// Address + // TODO: Make it Address-bookable + address: String, +} + +pub struct QueryNativeOutput; + +impl QueryNativeOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + let denom = scope.denom.0.clone(); + + let chain_data: ChainRegistryData = chain.into(); + + let rt = Runtime::new()?; + + rt.block_on(async { + let grpc_channel = + GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + let mut client = QueryClient::new(grpc_channel); + if let Some(denom) = denom { + let response: tonic::Response = client + .balance(QueryBalanceRequest { + address: scope.address.clone(), + denom: denom.clone(), + }) + .await?; + let balance = response + .into_inner() + .balance + .map(proto_coin_to_std) + .unwrap_or(cosmwasm_std::Coin { + denom, + amount: Default::default(), + }); + println!("balance: {balance}") + } else { + let response: tonic::Response = client + .all_balances(QueryAllBalancesRequest { + address: scope.address.clone(), + pagination: None, + }) + .await?; + let balances: Vec = response + .into_inner() + .balances + .into_iter() + .map(proto_coin_to_std) + .collect(); + // `cosmwasm_std::Coins` have nice display + let coins = cosmwasm_std::Coins::try_from(balances).unwrap(); + println!("balances: {coins}") + } + + color_eyre::Result::<(), color_eyre::Report>::Ok(()) + })?; + + Ok(QueryNativeOutput) + } +} + +fn proto_coin_to_std(proto: Coin) -> cosmwasm_std::Coin { + cosmwasm_std::Coin { + denom: proto.denom, + amount: proto.amount.parse().unwrap(), + } +} diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs b/packages/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs similarity index 75% rename from packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs rename to packages/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index f04b50d9a..ee1354b25 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/cw20/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -1,11 +1,16 @@ use cosmwasm_std::Uint128; -use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; +use cw_orch::{ + daemon::{CosmTxResponse, DaemonAsync}, + tokio::runtime::Runtime, +}; + +use crate::log::LogOutput; use super::CosmosContext; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] -#[interactive_clap(output_context = TransferCw20Output)] +#[interactive_clap(output_context = SendCw20Output)] pub struct Cw20TransferCommands { /// Cw20 Address cw20_address: String, @@ -17,9 +22,9 @@ pub struct Cw20TransferCommands { signer: String, } -pub struct TransferCw20Output; +pub struct SendCw20Output; -impl TransferCw20Output { +impl SendCw20Output { fn from_previous_context( previous_context: CosmosContext, scope: &::InteractiveClapContextScope, @@ -33,7 +38,7 @@ impl TransferCw20Output { let msg = serde_json::to_vec(&cw20_msg)?; let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) @@ -46,11 +51,13 @@ impl TransferCw20Output { msg, funds: vec![], }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + color_eyre::Result::::Ok(resp) })?; - Ok(TransferCw20Output) + resp.log(); + + Ok(SendCw20Output) } } diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs b/packages/cw-orch-cli/src/commands/action/asset/send_native/mod.rs similarity index 66% rename from packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs rename to packages/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 02fd236a7..83a55e1db 100644 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/native/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -1,14 +1,17 @@ use color_eyre::eyre::Context; -use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; +use cw_orch::{ + daemon::{CosmTxResponse, DaemonAsync}, + tokio::runtime::Runtime, +}; -use crate::types::CliCoins; +use crate::{log::LogOutput, types::CliCoins}; use super::CosmosContext; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] -#[interactive_clap(output_context = TransferNativeOutput)] -pub struct NativeTransferCommands { +#[interactive_clap(output_context = SendNativeOutput)] +pub struct SendNativeCommands { #[interactive_clap(skip_default_input_arg)] /// Input coins coins: CliCoins, @@ -18,7 +21,7 @@ pub struct NativeTransferCommands { signer: String, } -impl NativeTransferCommands { +impl SendNativeCommands { fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) @@ -26,12 +29,12 @@ impl NativeTransferCommands { } } -pub struct TransferNativeOutput; +pub struct SendNativeOutput; -impl TransferNativeOutput { +impl SendNativeOutput { fn from_previous_context( previous_context: CosmosContext, - scope: &::InteractiveClapContextScope, + scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; let seed = crate::common::seed_phrase_for_id(&scope.signer)?; @@ -39,7 +42,7 @@ impl TransferNativeOutput { let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) @@ -51,11 +54,13 @@ impl TransferNativeOutput { to_address: scope.to_address.parse()?, amount: coins, }; - let _res = daemon.sender.commit_tx(vec![transfer_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![transfer_msg], None).await?; - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + color_eyre::Result::::Ok(resp) })?; - Ok(TransferNativeOutput) + resp.log(); + + Ok(SendNativeOutput) } } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs similarity index 86% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 9b1670f8e..5f5e35d61 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/execute/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -1,9 +1,10 @@ use color_eyre::eyre::Context; -use cw_orch::{prelude::DaemonAsync, tokio::runtime::Runtime}; +use cw_orch::{daemon::CosmTxResponse, prelude::DaemonAsync, tokio::runtime::Runtime}; +use crate::log::LogOutput; use crate::{commands::action::CosmosContext, types::CliCoins}; -use super::super::msg_type; +use super::msg_type; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -52,7 +53,7 @@ impl ExecuteWasmOutput { let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) @@ -65,11 +66,13 @@ impl ExecuteWasmOutput { msg, funds: coins, }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + color_eyre::Result::::Ok(resp) })?; + resp.log(); + Ok(ExecuteWasmOutput) } } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs similarity index 86% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 0e298b42f..8de71a0db 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/instantiate/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -1,15 +1,15 @@ use color_eyre::eyre::Context; use cw_orch::{ prelude::{DaemonAsync, IndexResponse}, - tokio::runtime::Runtime, + tokio::runtime::Runtime, daemon::CosmTxResponse, }; use crate::{ commands::action::CosmosContext, - types::{CliCoins, CliSkippable}, + types::{CliCoins, CliSkippable}, log::LogOutput, }; -use super::super::msg_type; +use super::msg_type; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -73,7 +73,7 @@ impl InstantiateWasmOutput { let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) @@ -88,14 +88,14 @@ impl InstantiateWasmOutput { msg, funds: coins, }; - let res = daemon.sender.commit_tx(vec![exec_msg], None).await?; - let address = res.instantiated_contract_address()?; - - println!("Address of the instantiated contract: {address}"); - - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + color_eyre::Result::::Ok(resp) })?; + let address = resp.instantiated_contract_address()?; + resp.log(); + println!("Address of the instantiated contract: {address}"); + Ok(InstantiateWasmOutput) } } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/mod.rs similarity index 60% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/mod.rs index cf7f73021..90783e2f4 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/mod.rs @@ -1,30 +1,35 @@ -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - -use crate::commands::action::CosmosContext; - mod execute; mod instantiate; +pub mod msg_type; +mod query; mod store; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +use super::CosmosContext; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(context = CosmosContext)] -pub struct TxCommands { +pub struct CwCommands { #[interactive_clap(subcommand)] - action: TxAction, + action: CwAction, } #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] #[interactive_clap(context = CosmosContext)] /// Select cosmwasm action -pub enum TxAction { +pub enum CwAction { /// Store contract - #[strum_discriminants(strum(message = "Store contract"))] + #[strum_discriminants(strum(message = "📤Store contract"))] Store(store::StoreContractCommands), /// Instantiate contract - #[strum_discriminants(strum(message = "Instantiate contract"))] + #[strum_discriminants(strum(message = "🚀Instantiate contract"))] Instantiate(instantiate::InstantiateContractCommands), /// Execute contract method - #[strum_discriminants(strum(message = "Execute contract method"))] + #[strum_discriminants(strum(message = "⚡Execute contract method"))] Execute(execute::ExecuteContractCommands), + /// Query contract + #[strum_discriminants(strum(message = "🔍Query"))] + Query(query::QueryCommands), } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/msg_type/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/msg_type/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs similarity index 85% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs index c24d1dc6b..e8050b346 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs @@ -18,9 +18,9 @@ pub struct QueryCommands { /// Select cosmwasm action pub enum QueryAction { /// Query wasm smart - #[strum_discriminants(strum(message = "Smart"))] + #[strum_discriminants(strum(message = "🤓Smart"))] Smart(smart::QuerySmartCommands), /// Query wasm raw state - #[strum_discriminants(strum(message = "Raw"))] + #[strum_discriminants(strum(message = "👉Raw"))] Raw(raw::QueryRawCommands), } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs similarity index 74% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index 5adb70594..e26781170 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/raw/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -1,4 +1,6 @@ -use cosmrs::proto::cosmwasm::wasm::v1::{query_client::QueryClient, QueryRawContractStateRequest}; +use cosmrs::proto::cosmwasm::wasm::v1::{ + query_client::QueryClient, QueryRawContractStateRequest, QueryRawContractStateResponse, +}; use cw_orch::{ daemon::{ChainRegistryData, GrpcChannel}, tokio::runtime::Runtime, @@ -29,7 +31,7 @@ impl QueryWasmOutput { let chain_data: ChainRegistryData = chain.into(); let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let grpc_channel = GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; let mut client = QueryClient::new(grpc_channel); @@ -41,11 +43,14 @@ impl QueryWasmOutput { }) .await?; - let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + color_eyre::Result::::Ok( + resp.into_inner(), + ) })?; + let parsed_output: serde_json::Value = serde_json::from_slice(&resp.data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); + Ok(QueryWasmOutput) } } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs similarity index 81% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index a401723e1..b33e137d2 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/query/smart/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -1,5 +1,5 @@ use cosmrs::proto::cosmwasm::wasm::v1::{ - query_client::QueryClient, QuerySmartContractStateRequest, + query_client::QueryClient, QuerySmartContractStateRequest, QuerySmartContractStateResponse, }; use cw_orch::{ daemon::{ChainRegistryData, GrpcChannel}, @@ -44,7 +44,7 @@ impl QueryWasmOutput { let chain_data: ChainRegistryData = chain.into(); let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let grpc_channel = GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; let mut client = QueryClient::new(grpc_channel); @@ -55,10 +55,12 @@ impl QueryWasmOutput { query_data: msg, }) .await?; - let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + color_eyre::Result::::Ok( + resp.into_inner(), + ) })?; + let parsed_output: serde_json::Value = serde_json::from_slice(&resp.data)?; + println!("{}", serde_json::to_string_pretty(&parsed_output)?); Ok(QueryWasmOutput) } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs similarity index 78% rename from packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs rename to packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index 4ca7b57c5..c8445e620 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/tx/store/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -1,10 +1,10 @@ use color_eyre::eyre::Context; use cw_orch::{ prelude::{DaemonAsync, IndexResponse}, - tokio::runtime::Runtime, + tokio::runtime::Runtime, daemon::CosmTxResponse, }; -use crate::commands::action::CosmosContext; +use crate::{commands::action::CosmosContext, log::LogOutput}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -33,7 +33,7 @@ impl StoreWasmOutput { ))?; let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) @@ -45,17 +45,14 @@ impl StoreWasmOutput { wasm_byte_code, instantiate_permission: None, }; - let result = daemon.sender.commit_tx(vec![exec_msg], None).await?; - - println!("Uploaded: {:?}", result.txhash); - - let code_id = result.uploaded_code_id().unwrap(); - - println!("code_id: {code_id}"); - - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + color_eyre::Result::::Ok(resp) })?; + let code_id = resp.uploaded_code_id().unwrap(); + resp.log(); + println!("code_id: {code_id}"); + Ok(StoreWasmOutput) } } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs deleted file mode 100644 index cdb7b47e8..000000000 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm_tx/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -pub mod msg_type; -mod query; -mod tx; - -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - -use super::CosmosContext; - -#[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(context = CosmosContext)] -pub struct CwCommands { - #[interactive_clap(subcommand)] - action: CwAction, -} - -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = CosmosContext)] -/// Select cosmwasm action -pub enum CwAction { - /// Transaction - #[strum_discriminants(strum(message = "Transaction"))] - Tx(tx::TxCommands), - /// Query - #[strum_discriminants(strum(message = "Query"))] - Query(query::QueryCommands), -} diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs b/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs index a33cb8557..bb6ad9921 100644 --- a/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs @@ -35,15 +35,15 @@ pub struct CwOwnableCommands { /// Select cosmwasm action pub enum CwOwnableAction { /// Propose to transfer contract ownership to another address - #[strum_discriminants(strum(message = "Propose ownership to another address."))] + #[strum_discriminants(strum(message = "💍Propose ownership to another address."))] Transfer(transfer::TransferOwnership), /// Accept pending ownership - #[strum_discriminants(strum(message = "Accept pending ownership."))] + #[strum_discriminants(strum(message = "✅Accept pending ownership."))] Accept(accept::AcceptOwnership), // /// Renounce pending ownership - #[strum_discriminants(strum(message = "Renounce pending ownership"))] + #[strum_discriminants(strum(message = "🚫Renounce pending ownership"))] Renounce(renounce::RenounceOwnership), /// Get current ownership - #[strum_discriminants(strum(message = "Get current ownership"))] + #[strum_discriminants(strum(message = "❓Get current ownership"))] Get(get::GetOwnership), } diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index 6bf8ae9ee..8d588b63f 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -1,6 +1,6 @@ -mod cosmwasm_tx; +mod cosmwasm; mod cw_ownable; -mod transfer_tx; +mod asset; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; @@ -22,15 +22,14 @@ pub struct CosmosCommands { #[interactive_clap(context = CosmosContext)] /// Select type of cosmos action pub enum CosmosAction { - /// Cosmwasm Action - #[strum_discriminants(strum(message = "CosmWasm"))] - Cw(cosmwasm_tx::CwCommands), - // TODO: rename and expand to bank? - // /// Transfer Action - #[strum_discriminants(strum(message = "Transfer"))] - Transfer(transfer_tx::TransferCommands), + /// Cosmwasm Action: store, instantiate, execute or query cosmwasm contract + #[strum_discriminants(strum(message = "🔮CosmWasm"))] + Cw(cosmwasm::CwCommands), + /// Asset Action + #[strum_discriminants(strum(message = "🏦Asset"))] + Asset(asset::AssetCommands), /// CW-Ownable Action - #[strum_discriminants(strum(message = "CW-Ownable"))] + #[strum_discriminants(strum(message = "👑CW-Ownable"))] CwOwnable(cw_ownable::CwOwnableCommands), } diff --git a/packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs b/packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs deleted file mode 100644 index 7b7c2a040..000000000 --- a/packages/cw-orch-cli/src/commands/action/transfer_tx/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -mod cw20; -mod native; - -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - -use super::CosmosContext; - -#[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(context = CosmosContext)] -pub struct TransferCommands { - #[interactive_clap(subcommand)] - action: TransferAction, -} - -#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] -#[strum_discriminants(derive(EnumMessage, EnumIter))] -#[interactive_clap(context = CosmosContext)] -/// Select cosmwasm action -pub enum TransferAction { - /// Transfer native coins - #[strum_discriminants(strum(message = "Transfer native coins"))] - Native(native::NativeTransferCommands), - /// Transfer cw20 coin - #[strum_discriminants(strum(message = "Transfer cw20 coin"))] - Cw20(cw20::Cw20TransferCommands), - // TODO: cw720? -} diff --git a/packages/cw-orch-cli/src/commands/keys/mod.rs b/packages/cw-orch-cli/src/commands/keys/mod.rs index 0f089287a..95c7d1477 100644 --- a/packages/cw-orch-cli/src/commands/keys/mod.rs +++ b/packages/cw-orch-cli/src/commands/keys/mod.rs @@ -16,15 +16,15 @@ pub struct KeyCommands { /// Select key action pub enum KeyAction { /// Add key to the keyring - #[strum_discriminants(strum(message = "Add key to the keyring"))] + #[strum_discriminants(strum(message = "📝Add key to the keyring"))] Add(add_key::AddKeyCommand), /// Show seed from keyring - #[strum_discriminants(strum(message = "Show key of given id from the keyring"))] + #[strum_discriminants(strum(message = "🔐Show key of given id from the keyring"))] Show(show_key::ShowKeyCommand), /// Remove key from the keyring - #[strum_discriminants(strum(message = "Remove key from the keyring"))] + #[strum_discriminants(strum(message = "❌Remove key from the keyring"))] Remove(remove_key::RemoveKeyCommand), /// Show address of the key - #[strum_discriminants(strum(message = "Show address of the key"))] + #[strum_discriminants(strum(message = "📌Show address of the key"))] ShowAddress(show_address::ShowAddressCommand), } diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index d48c42ab6..ebee26eea 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -7,10 +7,13 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[strum_discriminants(derive(EnumMessage, EnumIter))] /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { - /// Action - #[strum_discriminants(strum(message = "Action"))] + /// Select action + #[strum_discriminants(strum(message = "⚙️ Action"))] Action(action::CosmosCommands), /// Add, View or Remove key - #[strum_discriminants(strum(message = "Manage keys"))] + #[strum_discriminants(strum(message = "🔑Manage keys"))] Key(keys::KeyCommands), + // TODO: + // 1) AddressBook + // 2) Config management } diff --git a/packages/cw-orch-cli/src/log/mod.rs b/packages/cw-orch-cli/src/log/mod.rs new file mode 100644 index 000000000..78dd373a1 --- /dev/null +++ b/packages/cw-orch-cli/src/log/mod.rs @@ -0,0 +1,11 @@ +use cw_orch::daemon::CosmTxResponse; + +pub trait LogOutput { + fn log(&self); +} + +impl LogOutput for CosmTxResponse { + fn log(&self) { + println!("Transaction hash: {}", self.txhash); + } +} diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index 5c7df304b..33b755aeb 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,5 +1,6 @@ mod commands; mod common; +mod log; pub(crate) mod types; use interactive_clap::{ResultFromCli, ToCliArgs}; @@ -10,7 +11,7 @@ pub struct TLCommand { } fn main() -> color_eyre::Result<()> { - // We don't want to see logs in stdout during cli + // We don't want to see cw-orch logs during cli std::env::set_var("CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE", "true"); // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); From 1a295d8456b92098a7cc0208345046892bb3fb5f Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 21:05:31 +0200 Subject: [PATCH 065/135] initial readme --- packages/cw-orch-cli/README.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/cw-orch-cli/README.md b/packages/cw-orch-cli/README.md index 117f83b4a..3c001c1f6 100644 --- a/packages/cw-orch-cli/README.md +++ b/packages/cw-orch-cli/README.md @@ -1,12 +1,36 @@ -## Cw Orch CLI +# CosmWasm Orch Command Line Interface (CLI) -Cw Orch CLI is a command line utility for working with cosmos blockhains +The CosmWasm Orch CLI is a tool designed to facilitate the development, deployment, and interaction with CosmWasm smart contracts on Cosmos blockchains. It enables developers to create, test, and manage contracts using the interactive CLI and easily deploy them onto supported Cosmos networks. -## Add latest command to the history -You can add this function to ~/.bashrc to append the last executed command to the current session history: +# Installation + +## Prerequisites +It shares same prerequisites as Cw Orch, see [Prerequisites](../../INSTALL.md#prerequisites) + +## Install the Cosmwasm Orch CLI +```bash +cargo install cw-orch-cli +``` + +## Add latest command to the shell history (Optionally) +If Cw Orch CLI ran in interactive mode shell history will only save the command it was originally executed with. +For more enjoyable user experience you can add this function to ~/.bashrc to append the last executed command to the current session history: ```bash cw-orch-cli() { command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2 -d':') history -s $command } +``` + +# Usage + +## Interactive mode +Interactive mode simplifies complex tasks, reduces command complexity, and ensures a more intuitive user experience through real-time interaction. Which makes it preferred way of execution for users. + +## Non-interactive mode +Utilize the non-interactive mode for scripted tasks, automated operations, and efficient execution without manual interaction within the CW-Orchestrator CLI. + +Example: +```bash +cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms6q698938k529q3shmfl90 contract_info ``` \ No newline at end of file From 6e58e014f6a6d74824e2a4322afcd5bedc9035ff Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 21:32:14 +0200 Subject: [PATCH 066/135] cut out contract cli --- contracts/counter/Cargo.toml | 6 ++--- contracts/counter/examples/cli.rs | 2 +- contracts/counter/src/interface.rs | 4 ++-- contracts/counter/src/msg.rs | 8 +++---- packages/cw-orch-cli-derive/src/lib.rs | 12 +++++----- packages/cw-orch-cli/Cargo.toml | 7 +++--- .../action/cosmwasm/instantiate/mod.rs | 6 +++-- .../src/commands/action/cosmwasm/store/mod.rs | 5 ++-- .../cw-orch-cli/src/commands/action/mod.rs | 2 +- packages/cw-orch-cli/src/commands/mod.rs | 2 +- packages/cw-orch-cli/src/lib.rs | 23 +++---------------- packages/cw-orch-cli/src/main.rs | 6 ++--- packages/cw-orch-contract-cli/Cargo.toml | 21 +++++++++++++++++ .../src/contract/error.rs | 0 .../src/contract/mod.rs | 4 ++-- .../src/daemon/mod.rs | 0 packages/cw-orch-contract-cli/src/lib.rs | 18 +++++++++++++++ 17 files changed, 74 insertions(+), 52 deletions(-) create mode 100644 packages/cw-orch-contract-cli/Cargo.toml rename packages/{cw-orch-cli => cw-orch-contract-cli}/src/contract/error.rs (100%) rename packages/{cw-orch-cli => cw-orch-contract-cli}/src/contract/mod.rs (98%) rename packages/{cw-orch-cli => cw-orch-contract-cli}/src/daemon/mod.rs (100%) create mode 100644 packages/cw-orch-contract-cli/src/lib.rs diff --git a/contracts/counter/Cargo.toml b/contracts/counter/Cargo.toml index b5054dede..cc9603d62 100644 --- a/contracts/counter/Cargo.toml +++ b/contracts/counter/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib", "rlib"] [features] default = ["export"] export = [] -interface = ["dep:cw-orch", "dep:cw-orch-cli"] +interface = ["dep:cw-orch", "dep:cw-orch-contract-cli"] [dependencies] cosmwasm-std = { workspace = true } @@ -25,7 +25,7 @@ serde = { workspace = true } serde_json = "1.0.79" cw-orch = { path = "../../cw-orch", optional = true, features = ["daemon"] } -cw-orch-cli = { path = "../../packages/cw-orch-cli", optional = true } +cw-orch-contract-cli = { path = "../../packages/cw-orch-contract-cli", optional = true } [dev-dependencies] cw-multi-test = { workspace = true } @@ -34,5 +34,5 @@ counter-contract = { path = ".", features = ["interface"] } dotenv = { version = "0.15.0" } pretty_env_logger = { version = "0.5.0" } cw-orch = { path = "../../cw-orch", features = ["daemon", "osmosis-test-tube"] } -cw-orch-cli = { path = "../../packages/cw-orch-cli" } +cw-orch-contract-cli = { path = "../../packages/cw-orch-contract-cli" } anyhow.workspace = true diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index b174ac1ac..1f72326e4 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -1,7 +1,7 @@ use cosmwasm_std::Empty; use counter_contract::CounterContract; use cw_orch::{anyhow, prelude::Daemon, tokio::runtime::Runtime}; -use cw_orch_cli::{ContractCli, DaemonFromCli}; +use cw_orch_contract_cli::{ContractCli, DaemonFromCli}; pub fn main() -> anyhow::Result<()> { dotenv::dotenv().ok(); diff --git a/contracts/counter/src/interface.rs b/contracts/counter/src/interface.rs index 0d5ad5313..a6a4864b7 100644 --- a/contracts/counter/src/interface.rs +++ b/contracts/counter/src/interface.rs @@ -65,9 +65,9 @@ impl CounterContract { // ANCHOR_END: daemon // ANCHOR: cli -use cw_orch_cli::OrchCliResult; +use cw_orch_contract_cli::OrchCliResult; -impl cw_orch_cli::CwCliAddons for CounterContract { +impl cw_orch_contract_cli::CwCliAddons for CounterContract { fn addons(&mut self, _context: Empty) -> OrchCliResult<()> where Self: cw_orch::prelude::ContractInstance, diff --git a/contracts/counter/src/msg.rs b/contracts/counter/src/msg.rs index 009a7f047..fb2932bca 100644 --- a/contracts/counter/src/msg.rs +++ b/contracts/counter/src/msg.rs @@ -4,7 +4,7 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] +#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] /// Instantiate method for counter pub struct InstantiateMsg { /// Initial count @@ -13,7 +13,7 @@ pub struct InstantiateMsg { // ANCHOR: exec_msg #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] +#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] #[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))] // Function generation /// Execute methods for counter pub enum ExecuteMsg { @@ -29,7 +29,7 @@ pub enum ExecuteMsg { // ANCHOR: query_msg #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] +#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] #[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] // Function generation #[derive(QueryResponses)] /// Query methods for counter @@ -49,7 +49,7 @@ pub struct GetCountResponse { // ANCHOR_END: query_msg #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_cli::ParseCwMsg))] +#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] /// Migrate message for count contract pub struct MigrateMsg { /// Your favorite type of tea diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index b83e87937..d7dd8a2a7 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -69,12 +69,12 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { }); quote!( #[automatically_derived] - impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse(state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_cli::OrchCliResult { + impl ::cw_orch_contract_cli::ParseCwMsg for #name { + fn cw_parse(state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { #enum_of_variant_names #display_for_enum_variant_names let options = vec![#(#enum_variants_ident::#idents),*]; - let variant = ::cw_orch_cli::select_msg(options)?; + let variant = ::cw_orch_contract_cli::select_msg(options)?; #(#variants_as_structs)* let msg = match variant { #(#enum_variants_ident::#idents => #idents::cw_parse(state_interface)?.into()),* @@ -99,12 +99,12 @@ fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_mac let ident = field.ident.clone().unwrap(); let ty = field.ty.clone(); let message = format!("{}({})", ident, quote!(#ty)); - quote!(#ident: ::cw_orch_cli::custom_type_serialize(#message)?) + quote!(#ident: ::cw_orch_contract_cli::custom_type_serialize(#message)?) }); let derived_trait_impl = quote!( #[automatically_derived] - impl ::cw_orch_cli::ParseCwMsg for #name { - fn cw_parse(_state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_cli::OrchCliResult { + impl ::cw_orch_contract_cli::ParseCwMsg for #name { + fn cw_parse(_state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { Ok(Self { #(#fields),* }) diff --git a/packages/cw-orch-cli/Cargo.toml b/packages/cw-orch-cli/Cargo.toml index 99adce3d3..c3d27ec88 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/packages/cw-orch-cli/Cargo.toml @@ -14,12 +14,11 @@ directories = "5.0.1" keyring = "2.0.5" cosmrs = { version = "0.15.0", features = ["cosmwasm", "grpc"] } rand_core = { version = "0.6", features = ["std"] } -base64 = { version = "0.21.0" } # TODO: move to workspace +base64 = { version = "0.21.0" } # TODO: move to workspace cosmwasm-std = { version = "1.3" } cw-utils = "1.0.3" -cw-orch = { path = "../../cw-orch", features = ["daemon"] } -cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } -cw20 = { workspace = true } +cw-orch = { path = "../../cw-orch", features = ["daemon"], version = "0.19" } +cw20 = { version = "1" } interactive-clap = "0.2.4" interactive-clap-derive = "0.2.4" clap = { version = "4.0.18", features = ["derive"] } diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 8de71a0db..179520742 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -1,12 +1,14 @@ use color_eyre::eyre::Context; use cw_orch::{ + daemon::CosmTxResponse, prelude::{DaemonAsync, IndexResponse}, - tokio::runtime::Runtime, daemon::CosmTxResponse, + tokio::runtime::Runtime, }; use crate::{ commands::action::CosmosContext, - types::{CliCoins, CliSkippable}, log::LogOutput, + log::LogOutput, + types::{CliCoins, CliSkippable}, }; use super::msg_type; diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index c8445e620..4a0dde7c4 100644 --- a/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -1,7 +1,8 @@ use color_eyre::eyre::Context; use cw_orch::{ + daemon::CosmTxResponse, prelude::{DaemonAsync, IndexResponse}, - tokio::runtime::Runtime, daemon::CosmTxResponse, + tokio::runtime::Runtime, }; use crate::{commands::action::CosmosContext, log::LogOutput}; @@ -33,7 +34,7 @@ impl StoreWasmOutput { ))?; let rt = Runtime::new()?; - let resp = rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(seed) diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/packages/cw-orch-cli/src/commands/action/mod.rs index 8d588b63f..edb332e1a 100644 --- a/packages/cw-orch-cli/src/commands/action/mod.rs +++ b/packages/cw-orch-cli/src/commands/action/mod.rs @@ -1,6 +1,6 @@ +mod asset; mod cosmwasm; mod cw_ownable; -mod asset; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/packages/cw-orch-cli/src/commands/mod.rs index ebee26eea..f125a5163 100644 --- a/packages/cw-orch-cli/src/commands/mod.rs +++ b/packages/cw-orch-cli/src/commands/mod.rs @@ -13,7 +13,7 @@ pub enum Commands { /// Add, View or Remove key #[strum_discriminants(strum(message = "🔑Manage keys"))] Key(keys::KeyCommands), - // TODO: + // TODO: // 1) AddressBook // 2) Config management } diff --git a/packages/cw-orch-cli/src/lib.rs b/packages/cw-orch-cli/src/lib.rs index 91ea91293..41fd3e11b 100644 --- a/packages/cw-orch-cli/src/lib.rs +++ b/packages/cw-orch-cli/src/lib.rs @@ -1,21 +1,4 @@ -/// Allow integrating keys and stuff +pub mod commands; pub mod common; -pub mod types; - -mod contract; -mod daemon; - -pub use daemon::DaemonFromCli; - -pub use cw_orch_cli_derive::ParseCwMsg; - -pub use contract::{ - // Helpers used by derive macro - helpers::{custom_type_serialize, select_msg}, - AddonsContext, - ContractCli, - CwCliAddons, - OrchCliError, - OrchCliResult, - ParseCwMsg, -}; +pub(crate) mod log; +pub(crate) mod types; diff --git a/packages/cw-orch-cli/src/main.rs b/packages/cw-orch-cli/src/main.rs index 33b755aeb..1b71bac3d 100644 --- a/packages/cw-orch-cli/src/main.rs +++ b/packages/cw-orch-cli/src/main.rs @@ -1,7 +1,5 @@ -mod commands; -mod common; -mod log; -pub(crate) mod types; +use cw_orch_cli::{commands, common}; + use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] diff --git a/packages/cw-orch-contract-cli/Cargo.toml b/packages/cw-orch-contract-cli/Cargo.toml new file mode 100644 index 000000000..fca65e587 --- /dev/null +++ b/packages/cw-orch-contract-cli/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cw-orch-contract-cli" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } +thiserror = { workspace = true } +inquire = { version = "0.6" } +cw-orch = { path = "../../cw-orch", features = ["daemon"], version = "0.19" } +cw-orch-cli = { path = "../cw-orch-cli" } + +strum = { version = "0.24", features = ["derive"] } +cosmwasm-std = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } diff --git a/packages/cw-orch-cli/src/contract/error.rs b/packages/cw-orch-contract-cli/src/contract/error.rs similarity index 100% rename from packages/cw-orch-cli/src/contract/error.rs rename to packages/cw-orch-contract-cli/src/contract/error.rs diff --git a/packages/cw-orch-cli/src/contract/mod.rs b/packages/cw-orch-contract-cli/src/contract/mod.rs similarity index 98% rename from packages/cw-orch-cli/src/contract/mod.rs rename to packages/cw-orch-contract-cli/src/contract/mod.rs index 58fab9109..99b09bc31 100644 --- a/packages/cw-orch-cli/src/contract/mod.rs +++ b/packages/cw-orch-contract-cli/src/contract/mod.rs @@ -97,7 +97,7 @@ where fn instantiate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let instantiate_msg = ::InstantiateMsg::cw_parse(state_interface)?; - let coins = crate::common::parse_coins()?; + let coins = cw_orch_cli::common::parse_coins()?; let admin = Text::new("Admin addr") .with_help_message("Press ESC to not set admin") @@ -118,7 +118,7 @@ where fn execute_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; // TODO: figure out a way to make this only with `payable` attribute - let coins = crate::common::parse_coins()?; + let coins = cw_orch_cli::common::parse_coins()?; if helpers::confirm_action("Execute", &execute_msg, Some(&coins.to_vec()))? { let res = self.execute(&execute_msg, Some(&coins.to_vec()))?; diff --git a/packages/cw-orch-cli/src/daemon/mod.rs b/packages/cw-orch-contract-cli/src/daemon/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/daemon/mod.rs rename to packages/cw-orch-contract-cli/src/daemon/mod.rs diff --git a/packages/cw-orch-contract-cli/src/lib.rs b/packages/cw-orch-contract-cli/src/lib.rs new file mode 100644 index 000000000..8c589c917 --- /dev/null +++ b/packages/cw-orch-contract-cli/src/lib.rs @@ -0,0 +1,18 @@ +/// Allow integrating keys and stuff +mod contract; +mod daemon; + +pub use daemon::DaemonFromCli; + +pub use cw_orch_cli_derive::ParseCwMsg; + +pub use contract::{ + // Helpers used by derive macro + helpers::{custom_type_serialize, select_msg}, + AddonsContext, + ContractCli, + CwCliAddons, + OrchCliError, + OrchCliResult, + ParseCwMsg, +}; From 9203affbcd3cbbfa758c2b049805d794fb758942 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 21:35:19 +0200 Subject: [PATCH 067/135] move cw-orch-cli upper --- .../cw-orch-cli => cw-orch-cli}/Cargo.toml | 2 +- {packages/cw-orch-cli => cw-orch-cli}/README.md | 0 .../src/commands/action/asset/mod.rs | 0 .../src/commands/action/asset/query_cw20/mod.rs | 0 .../commands/action/asset/query_native/mod.rs | 0 .../src/commands/action/asset/send_cw20/mod.rs | 0 .../commands/action/asset/send_native/mod.rs | 0 .../src/commands/action/cosmwasm/execute/mod.rs | 0 .../commands/action/cosmwasm/instantiate/mod.rs | 0 .../src/commands/action/cosmwasm/mod.rs | 0 .../commands/action/cosmwasm/msg_type/mod.rs | 0 .../src/commands/action/cosmwasm/query/mod.rs | 0 .../commands/action/cosmwasm/query/raw/mod.rs | 0 .../commands/action/cosmwasm/query/smart/mod.rs | 0 .../src/commands/action/cosmwasm/store/mod.rs | 0 .../commands/action/cw_ownable/accept/mod.rs | 0 .../src/commands/action/cw_ownable/get/mod.rs | 0 .../src/commands/action/cw_ownable/mod.rs | 0 .../commands/action/cw_ownable/renounce/mod.rs | 0 .../commands/action/cw_ownable/transfer/mod.rs | 0 .../src/commands/action/mod.rs | 0 .../src/commands/keys/add_key/mod.rs | 0 .../src/commands/keys/mod.rs | 0 .../src/commands/keys/remove_key/mod.rs | 0 .../src/commands/keys/show_address/mod.rs | 0 .../src/commands/keys/show_key/mod.rs | 0 .../src/commands/mod.rs | 0 .../cw-orch-cli => cw-orch-cli}/src/common.rs | 0 .../cw-orch-cli => cw-orch-cli}/src/lib.rs | 0 .../cw-orch-cli => cw-orch-cli}/src/log/mod.rs | 0 .../cw-orch-cli => cw-orch-cli}/src/main.rs | 0 .../src/types/chain.rs | 0 .../src/types/coins.rs | 0 .../src/types/expiration.rs | 0 .../src/types/mod.rs | 0 .../src/types/path_buf.rs | 0 .../src/types/skippable.rs | 0 packages/cw-orch-cli/GUIDE.md | 17 ----------------- packages/cw-orch-contract-cli/Cargo.toml | 2 +- 39 files changed, 2 insertions(+), 19 deletions(-) rename {packages/cw-orch-cli => cw-orch-cli}/Cargo.toml (93%) rename {packages/cw-orch-cli => cw-orch-cli}/README.md (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/asset/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/asset/query_cw20/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/asset/query_native/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/asset/send_cw20/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/asset/send_native/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/execute/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/instantiate/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/msg_type/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/query/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/query/raw/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/query/smart/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cosmwasm/store/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cw_ownable/accept/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cw_ownable/get/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cw_ownable/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cw_ownable/renounce/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/cw_ownable/transfer/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/action/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/keys/add_key/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/keys/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/keys/remove_key/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/keys/show_address/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/keys/show_key/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/commands/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/common.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/lib.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/log/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/main.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/types/chain.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/types/coins.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/types/expiration.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/types/mod.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/types/path_buf.rs (100%) rename {packages/cw-orch-cli => cw-orch-cli}/src/types/skippable.rs (100%) delete mode 100644 packages/cw-orch-cli/GUIDE.md diff --git a/packages/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml similarity index 93% rename from packages/cw-orch-cli/Cargo.toml rename to cw-orch-cli/Cargo.toml index c3d27ec88..3e14740b9 100644 --- a/packages/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -17,7 +17,7 @@ rand_core = { version = "0.6", features = ["std"] } base64 = { version = "0.21.0" } # TODO: move to workspace cosmwasm-std = { version = "1.3" } cw-utils = "1.0.3" -cw-orch = { path = "../../cw-orch", features = ["daemon"], version = "0.19" } +cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.19" } cw20 = { version = "1" } interactive-clap = "0.2.4" interactive-clap-derive = "0.2.4" diff --git a/packages/cw-orch-cli/README.md b/cw-orch-cli/README.md similarity index 100% rename from packages/cw-orch-cli/README.md rename to cw-orch-cli/README.md diff --git a/packages/cw-orch-cli/src/commands/action/asset/mod.rs b/cw-orch-cli/src/commands/action/asset/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/asset/mod.rs rename to cw-orch-cli/src/commands/action/asset/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs rename to cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/asset/query_native/mod.rs rename to cw-orch-cli/src/commands/action/asset/query_native/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs rename to cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/asset/send_native/mod.rs rename to cw-orch-cli/src/commands/action/asset/send_native/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs rename to cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs rename to cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cw_ownable/mod.rs rename to cw-orch-cli/src/commands/action/cw_ownable/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs rename to cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs rename to cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs diff --git a/packages/cw-orch-cli/src/commands/action/mod.rs b/cw-orch-cli/src/commands/action/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/action/mod.rs rename to cw-orch-cli/src/commands/action/mod.rs diff --git a/packages/cw-orch-cli/src/commands/keys/add_key/mod.rs b/cw-orch-cli/src/commands/keys/add_key/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/keys/add_key/mod.rs rename to cw-orch-cli/src/commands/keys/add_key/mod.rs diff --git a/packages/cw-orch-cli/src/commands/keys/mod.rs b/cw-orch-cli/src/commands/keys/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/keys/mod.rs rename to cw-orch-cli/src/commands/keys/mod.rs diff --git a/packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs b/cw-orch-cli/src/commands/keys/remove_key/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/keys/remove_key/mod.rs rename to cw-orch-cli/src/commands/keys/remove_key/mod.rs diff --git a/packages/cw-orch-cli/src/commands/keys/show_address/mod.rs b/cw-orch-cli/src/commands/keys/show_address/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/keys/show_address/mod.rs rename to cw-orch-cli/src/commands/keys/show_address/mod.rs diff --git a/packages/cw-orch-cli/src/commands/keys/show_key/mod.rs b/cw-orch-cli/src/commands/keys/show_key/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/keys/show_key/mod.rs rename to cw-orch-cli/src/commands/keys/show_key/mod.rs diff --git a/packages/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/commands/mod.rs rename to cw-orch-cli/src/commands/mod.rs diff --git a/packages/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs similarity index 100% rename from packages/cw-orch-cli/src/common.rs rename to cw-orch-cli/src/common.rs diff --git a/packages/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs similarity index 100% rename from packages/cw-orch-cli/src/lib.rs rename to cw-orch-cli/src/lib.rs diff --git a/packages/cw-orch-cli/src/log/mod.rs b/cw-orch-cli/src/log/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/log/mod.rs rename to cw-orch-cli/src/log/mod.rs diff --git a/packages/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs similarity index 100% rename from packages/cw-orch-cli/src/main.rs rename to cw-orch-cli/src/main.rs diff --git a/packages/cw-orch-cli/src/types/chain.rs b/cw-orch-cli/src/types/chain.rs similarity index 100% rename from packages/cw-orch-cli/src/types/chain.rs rename to cw-orch-cli/src/types/chain.rs diff --git a/packages/cw-orch-cli/src/types/coins.rs b/cw-orch-cli/src/types/coins.rs similarity index 100% rename from packages/cw-orch-cli/src/types/coins.rs rename to cw-orch-cli/src/types/coins.rs diff --git a/packages/cw-orch-cli/src/types/expiration.rs b/cw-orch-cli/src/types/expiration.rs similarity index 100% rename from packages/cw-orch-cli/src/types/expiration.rs rename to cw-orch-cli/src/types/expiration.rs diff --git a/packages/cw-orch-cli/src/types/mod.rs b/cw-orch-cli/src/types/mod.rs similarity index 100% rename from packages/cw-orch-cli/src/types/mod.rs rename to cw-orch-cli/src/types/mod.rs diff --git a/packages/cw-orch-cli/src/types/path_buf.rs b/cw-orch-cli/src/types/path_buf.rs similarity index 100% rename from packages/cw-orch-cli/src/types/path_buf.rs rename to cw-orch-cli/src/types/path_buf.rs diff --git a/packages/cw-orch-cli/src/types/skippable.rs b/cw-orch-cli/src/types/skippable.rs similarity index 100% rename from packages/cw-orch-cli/src/types/skippable.rs rename to cw-orch-cli/src/types/skippable.rs diff --git a/packages/cw-orch-cli/GUIDE.md b/packages/cw-orch-cli/GUIDE.md deleted file mode 100644 index d28e9b27b..000000000 --- a/packages/cw-orch-cli/GUIDE.md +++ /dev/null @@ -1,17 +0,0 @@ -## User Guide -Before deciding what command you want to run you'll have to: -1. Chose one of the supported chains by the cw-orch. -2. Select signing method (optionally) - -### Command groups - -- wasm - Deploy, Instantiate, Query, Execute, Migrate smart contracts -- TODO?:bank - send coins, query bank balances, denom metadata. - -#### Wasm subcommands -- execute -- query (Signer not required) -- instantiate -- deploy -- migrate - diff --git a/packages/cw-orch-contract-cli/Cargo.toml b/packages/cw-orch-contract-cli/Cargo.toml index fca65e587..4b7c14037 100644 --- a/packages/cw-orch-contract-cli/Cargo.toml +++ b/packages/cw-orch-contract-cli/Cargo.toml @@ -13,7 +13,7 @@ cw-orch-cli-derive = { path = "../cw-orch-cli-derive", version = "0.13.3" } thiserror = { workspace = true } inquire = { version = "0.6" } cw-orch = { path = "../../cw-orch", features = ["daemon"], version = "0.19" } -cw-orch-cli = { path = "../cw-orch-cli" } +cw-orch-cli = { path = "../../cw-orch-cli" } strum = { version = "0.24", features = ["derive"] } cosmwasm-std = { workspace = true } From 569bbf938195af5cd9e7523717b13d6ca751410f Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 21:38:13 +0200 Subject: [PATCH 068/135] update authors --- cw-orch-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 3e14740b9..fc88f4678 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cw-orch-cli" version = "0.1.0" -authors.workspace = true +authors = ["Buckram "] edition.workspace = true license.workspace = true repository.workspace = true From c254301b5d6f191168b74cb541aaa7d508dfe0e3 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 22 Dec 2023 21:44:26 +0200 Subject: [PATCH 069/135] small description --- cw-orch-cli/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index fc88f4678..c8e73a270 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Buckram "] edition.workspace = true license.workspace = true repository.workspace = true +description = "Command-line tool for managing Cosmos-based interaction." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 3d443c0c5e0460303aeeca2be94993d95ffbdd93 Mon Sep 17 00:00:00 2001 From: Mykhailo Donchenko <91957742+Buckram123@users.noreply.github.com> Date: Fri, 22 Dec 2023 22:31:33 +0200 Subject: [PATCH 070/135] Fix link --- cw-orch-cli/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index 3c001c1f6..2092950a7 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -5,7 +5,7 @@ The CosmWasm Orch CLI is a tool designed to facilitate the development, deployme # Installation ## Prerequisites -It shares same prerequisites as Cw Orch, see [Prerequisites](../../INSTALL.md#prerequisites) +It shares same prerequisites as Cw Orch, see [Prerequisites](../INSTALL.md#prerequisites) ## Install the Cosmwasm Orch CLI ```bash @@ -33,4 +33,4 @@ Utilize the non-interactive mode for scripted tasks, automated operations, and e Example: ```bash cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms6q698938k529q3shmfl90 contract_info -``` \ No newline at end of file +``` From 1454e1769d14d5bcf7bbc15f5435bed0254cfe4e Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 29 Dec 2023 13:44:31 +0200 Subject: [PATCH 071/135] structure Cargo.toml --- Cargo.toml | 1 + cw-orch-cli/Cargo.toml | 38 +++++++++++++++++++------------------- cw-orch-daemon/Cargo.toml | 2 +- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 02e81e6e0..22e8c9d13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ cw-orch-networks = { path = "packages/cw-orch-networks", version = "0.19.0" } thiserror = { version = "1.0.21" } sha256 = { version = "1" } serde_json = "1.0.79" +base64 = { version = "0.21.0" } tonic = { version = "0.10.2" } prost-types = "0.11.9" prost = "0.11.9" diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index c8e73a270..b0ab3a894 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -10,31 +10,31 @@ description = "Command-line tool for managing Cosmos-based interaction." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -thiserror = { workspace = true } -directories = "5.0.1" -keyring = "2.0.5" -cosmrs = { version = "0.15.0", features = ["cosmwasm", "grpc"] } -rand_core = { version = "0.6", features = ["std"] } -base64 = { version = "0.21.0" } # TODO: move to workspace -cosmwasm-std = { version = "1.3" } -cw-utils = "1.0.3" cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.19" } + +# Cosmos +cosmwasm-std = { workspace = true } +cw-utils = "1.0.3" cw20 = { version = "1" } +cw-ownable = { version = "0.5.1" } +cosmrs = { version = "0.15.0", features = ["cosmwasm", "grpc"] } + +# Serde +serde_json = { workspace = true } +serde = { workspace = true } +base64 = { workspace = true } + +# Interactive clap interactive-clap = "0.2.4" interactive-clap-derive = "0.2.4" clap = { version = "4.0.18", features = ["derive"] } color-eyre = { version = "0.6" } -inquire = { version = "0.6" } strum = { version = "0.24", features = ["derive"] } -bip32 = { version = "0.5", features = ["mnemonic"] } -dotenv = { version = "0.15.0" } - -serde_json = "1.0.79" -serde = { workspace = true } -log = "0.4.14" -shell-words = "1.0.0" - -tonic = "0.10.0" derive_more = "0.99" +shell-words = "1.0.0" +inquire = { version = "0.6" } -cw-ownable = { version = "0.5.1" } +# Key management +keyring = "2.0.5" +bip32 = { version = "0.5", features = ["mnemonic"] } +rand_core = { version = "0.6", features = ["std"] } diff --git a/cw-orch-daemon/Cargo.toml b/cw-orch-daemon/Cargo.toml index 11c7118a9..c248b8aad 100644 --- a/cw-orch-daemon/Cargo.toml +++ b/cw-orch-daemon/Cargo.toml @@ -49,7 +49,7 @@ tokio = { version = "1.4", features = ["full"] } tonic = { workspace = true, features = ["tls", "tls-roots"] } secp256k1 = { version = "0.27.0", default-features = false } reqwest = { version = "0.11.9" } -base64 = { version = "0.21.0" } +base64 = { workspace = true } hkd32 = { version = "0.7.0", features = ["bip39", "mnemonic", "bech32"] } rand_core = { version = "0.6.4", default-features = false } ed25519-dalek = { version = "2", features = ["serde"] } From 3cd7630c7c644831455f550f8f836ec74fbb1306 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 29 Dec 2023 13:49:09 +0200 Subject: [PATCH 072/135] remove tonic --- .../commands/action/asset/query_native/mod.rs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index 40c0a9eb0..5bb845060 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -44,30 +44,31 @@ impl QueryNativeOutput { GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; let mut client = QueryClient::new(grpc_channel); if let Some(denom) = denom { - let response: tonic::Response = client + let response: QueryBalanceResponse = client .balance(QueryBalanceRequest { address: scope.address.clone(), denom: denom.clone(), }) - .await?; - let balance = response - .into_inner() - .balance - .map(proto_coin_to_std) - .unwrap_or(cosmwasm_std::Coin { - denom, - amount: Default::default(), - }); + .await? + .into_inner(); + let balance = + response + .balance + .map(proto_coin_to_std) + .unwrap_or(cosmwasm_std::Coin { + denom, + amount: Default::default(), + }); println!("balance: {balance}") } else { - let response: tonic::Response = client + let response: QueryAllBalancesResponse = client .all_balances(QueryAllBalancesRequest { address: scope.address.clone(), pagination: None, }) - .await?; + .await? + .into_inner(); let balances: Vec = response - .into_inner() .balances .into_iter() .map(proto_coin_to_std) From ce90ec21154f55244ac058790bf1f9d8a016cca3 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 29 Dec 2023 16:37:18 +0200 Subject: [PATCH 073/135] keys docs --- cw-orch-cli/README.md | 3 ++- cw-orch-cli/src/commands/keys/mod.rs | 4 ++-- docs/src/SUMMARY.md | 3 +++ docs/src/cli/index.md | 23 +++++++++++++++++++++++ docs/src/cli/keys.md | 28 ++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 docs/src/cli/index.md create mode 100644 docs/src/cli/keys.md diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index 2092950a7..a80196afd 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -5,7 +5,8 @@ The CosmWasm Orch CLI is a tool designed to facilitate the development, deployme # Installation ## Prerequisites -It shares same prerequisites as Cw Orch, see [Prerequisites](../INSTALL.md#prerequisites) +- Rust +- OpenSSL ## Install the Cosmwasm Orch CLI ```bash diff --git a/cw-orch-cli/src/commands/keys/mod.rs b/cw-orch-cli/src/commands/keys/mod.rs index 95c7d1477..6c3bb67c1 100644 --- a/cw-orch-cli/src/commands/keys/mod.rs +++ b/cw-orch-cli/src/commands/keys/mod.rs @@ -24,7 +24,7 @@ pub enum KeyAction { /// Remove key from the keyring #[strum_discriminants(strum(message = "❌Remove key from the keyring"))] Remove(remove_key::RemoveKeyCommand), - /// Show address of the key - #[strum_discriminants(strum(message = "📌Show address of the key"))] + /// Show address + #[strum_discriminants(strum(message = "📌Show address"))] ShowAddress(show_address::ShowAddressCommand), } diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index eab539577..4032acd73 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -44,6 +44,9 @@ - [Sei](./chains/sei.md) - [Terra](./chains/terra.md) +- [CLI](./cli/index.md) + - [Keys](./cli/keys.md) + # Extras - [CI/CD](./ci-cd.md) diff --git a/docs/src/cli/index.md b/docs/src/cli/index.md new file mode 100644 index 000000000..35f825c7b --- /dev/null +++ b/docs/src/cli/index.md @@ -0,0 +1,23 @@ +# Orchestrator Command Line Interface (CLI) + +Currently, each chain has its own CLI based on wasmd, which are incompatible with each other. With this in mind, we created cw-orch-cli. cw-orchestrator allows for easy chain switching, which is essential for cross-chain solutions. + +## Prerequisites + +- Rust +- OpenSSL + +## Setup + +```bash +cargo install cw-orch-cli +``` + +## Features + +Supported features of cw-orch-cli: + +- **[Keys management](./keys.md)** + - Add, show or remove key from/into keyring + +Feel free to request new features by [opening an issue](https://github.com/AbstractSDK/cw-orchestrator/issues/new)! \ No newline at end of file diff --git a/docs/src/cli/keys.md b/docs/src/cli/keys.md new file mode 100644 index 000000000..78885664a --- /dev/null +++ b/docs/src/cli/keys.md @@ -0,0 +1,28 @@ +# Key management + +To sign transactions, you need to have a stored key in the keyring. This is currently the only way to sign transactions, feel free to request other signing methods. + +## Safety +The keys are kept in an underlying platform-specific secure store(keyring) as seeds. To support different derivation paths we can't save it as key pair + +## Features + +#### Add key + +Add key command saves provided or generated seed to the keyring +- Generate new random seed : `cw-orch-cli key add [NAME] new` +- Recover from seed phrase: `cw-orch-cli key add [NAME] from-seed` + - This command will give you prompt +#### Show seed of saved key + +Show seed command loads saved seed phrase from keyring and outputs it +- Shows seed phrase of the key: `cw-orch-cli key show [NAME]` + +#### Show address + +Show address command generates public address for this key on chosen network +- Show address: `cw-orch-cli key show-address [NAME] [CHAIN_ID]` +#### Remove key + +Remove key command deletes entry of provided key-id from the keyring +- Removes key: `cw-orch-cli key remove [NAME]` \ No newline at end of file From bac10878d44624b768be0bf2608f77bdea6ee040 Mon Sep 17 00:00:00 2001 From: cyberhoward Date: Wed, 3 Jan 2024 15:11:40 +0100 Subject: [PATCH 074/135] update readme and some prompts --- cw-orch-cli/README.md | 36 ++++++++++++------- .../src/commands/action/cosmwasm/mod.rs | 6 ++-- .../commands/action/cosmwasm/msg_type/mod.rs | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index a80196afd..700277a57 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -8,30 +8,42 @@ The CosmWasm Orch CLI is a tool designed to facilitate the development, deployme - Rust - OpenSSL -## Install the Cosmwasm Orch CLI +## Cargo + ```bash cargo install cw-orch-cli ``` -## Add latest command to the shell history (Optionally) -If Cw Orch CLI ran in interactive mode shell history will only save the command it was originally executed with. -For more enjoyable user experience you can add this function to ~/.bashrc to append the last executed command to the current session history: +### Add last command to the shell history (Optional) + +If Cw Orch CLI ran in interactive mode it's executed command will **not** be appended to your shell history. This means you will not be able to `arrow up` to get the last command and tweak it to your liking. + +To solve this you can add the function below to your `~/.bashrc` or similar. +This function wraps the CLI and appends its executed action to your current shell history, enabling you to retrieve it from the history. + ```bash cw-orch-cli() { - command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2 -d':') - history -s $command + command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2 -d':') + history -s $command } ``` -# Usage +## Usage + +The CLI supports two modes of execution: interactive and non-interactive. + +### Interactive mode + +In interactive mode the CLI will guide you through complex tasks by reducing the initial command's complexity, and ensuring a more intuitive user experience. + +The interactive mode will prompt you for new information when needed as you go through the process of creating, testing, and deploying a contract. + +### Non-interactive mode -## Interactive mode -Interactive mode simplifies complex tasks, reduces command complexity, and ensures a more intuitive user experience through real-time interaction. Which makes it preferred way of execution for users. +You can utilize the non-interactive mode for scripting, automated operations, and tweaking of the interactive mode's commands. Often you'll find yourself using the interactive mode to get the command you need, and then debug it with the non-interactive mode. -## Non-interactive mode -Utilize the non-interactive mode for scripted tasks, automated operations, and efficient execution without manual interaction within the CW-Orchestrator CLI. +Example: -Example: ```bash cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms6q698938k529q3shmfl90 contract_info ``` diff --git a/cw-orch-cli/src/commands/action/cosmwasm/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs index 90783e2f4..0ce09aa66 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs @@ -21,13 +21,13 @@ pub struct CwCommands { /// Select cosmwasm action pub enum CwAction { /// Store contract - #[strum_discriminants(strum(message = "📤Store contract"))] + #[strum_discriminants(strum(message = "📤Store"))] Store(store::StoreContractCommands), /// Instantiate contract - #[strum_discriminants(strum(message = "🚀Instantiate contract"))] + #[strum_discriminants(strum(message = "🚀Instantiate"))] Instantiate(instantiate::InstantiateContractCommands), /// Execute contract method - #[strum_discriminants(strum(message = "⚡Execute contract method"))] + #[strum_discriminants(strum(message = "⚡Execute"))] Execute(execute::ExecuteContractCommands), /// Query contract #[strum_discriminants(strum(message = "🔍Query"))] diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index 6935eaad9..b4cf87b7f 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -52,7 +52,7 @@ impl std::fmt::Display for MsgTypeDiscriminants { pub fn input_msg_type() -> color_eyre::eyre::Result> { let variants = MsgTypeDiscriminants::iter().collect::>(); - let selected = Select::new("How would you like to proceed?", variants).prompt()?; + let selected = Select::new("Select message format", variants).prompt()?; match selected { MsgTypeDiscriminants::JsonMsg => Ok(Some(MsgType::JsonMsg)), MsgTypeDiscriminants::Base64Msg => Ok(Some(MsgType::Base64Msg)), From 86eea24bfa6104f25b68049f53e847deb18ac6c0 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Jan 2024 13:39:00 +0200 Subject: [PATCH 075/135] add spaces for emojis --- cw-orch-cli/src/commands/action/cosmwasm/mod.rs | 8 ++++---- cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs | 4 ++-- cw-orch-cli/src/commands/action/mod.rs | 6 +++--- cw-orch-cli/src/commands/keys/mod.rs | 8 ++++---- cw-orch-cli/src/commands/mod.rs | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs index 0ce09aa66..b7ee29205 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs @@ -21,15 +21,15 @@ pub struct CwCommands { /// Select cosmwasm action pub enum CwAction { /// Store contract - #[strum_discriminants(strum(message = "📤Store"))] + #[strum_discriminants(strum(message = "📤 Store"))] Store(store::StoreContractCommands), /// Instantiate contract - #[strum_discriminants(strum(message = "🚀Instantiate"))] + #[strum_discriminants(strum(message = "🚀 Instantiate"))] Instantiate(instantiate::InstantiateContractCommands), /// Execute contract method - #[strum_discriminants(strum(message = "⚡Execute"))] + #[strum_discriminants(strum(message = "⚡ Execute"))] Execute(execute::ExecuteContractCommands), /// Query contract - #[strum_discriminants(strum(message = "🔍Query"))] + #[strum_discriminants(strum(message = "🔍 Query"))] Query(query::QueryCommands), } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs index e8050b346..7dcc5671a 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs @@ -18,9 +18,9 @@ pub struct QueryCommands { /// Select cosmwasm action pub enum QueryAction { /// Query wasm smart - #[strum_discriminants(strum(message = "🤓Smart"))] + #[strum_discriminants(strum(message = "🤓 Smart"))] Smart(smart::QuerySmartCommands), /// Query wasm raw state - #[strum_discriminants(strum(message = "👉Raw"))] + #[strum_discriminants(strum(message = "👉 Raw"))] Raw(raw::QueryRawCommands), } diff --git a/cw-orch-cli/src/commands/action/mod.rs b/cw-orch-cli/src/commands/action/mod.rs index edb332e1a..5de10fd5d 100644 --- a/cw-orch-cli/src/commands/action/mod.rs +++ b/cw-orch-cli/src/commands/action/mod.rs @@ -23,13 +23,13 @@ pub struct CosmosCommands { /// Select type of cosmos action pub enum CosmosAction { /// Cosmwasm Action: store, instantiate, execute or query cosmwasm contract - #[strum_discriminants(strum(message = "🔮CosmWasm"))] + #[strum_discriminants(strum(message = "🔮 CosmWasm"))] Cw(cosmwasm::CwCommands), /// Asset Action - #[strum_discriminants(strum(message = "🏦Asset"))] + #[strum_discriminants(strum(message = "🏦 Asset"))] Asset(asset::AssetCommands), /// CW-Ownable Action - #[strum_discriminants(strum(message = "👑CW-Ownable"))] + #[strum_discriminants(strum(message = "👑 CW-Ownable"))] CwOwnable(cw_ownable::CwOwnableCommands), } diff --git a/cw-orch-cli/src/commands/keys/mod.rs b/cw-orch-cli/src/commands/keys/mod.rs index 6c3bb67c1..c6cf202a2 100644 --- a/cw-orch-cli/src/commands/keys/mod.rs +++ b/cw-orch-cli/src/commands/keys/mod.rs @@ -16,15 +16,15 @@ pub struct KeyCommands { /// Select key action pub enum KeyAction { /// Add key to the keyring - #[strum_discriminants(strum(message = "📝Add key to the keyring"))] + #[strum_discriminants(strum(message = "📝 Add key to the keyring"))] Add(add_key::AddKeyCommand), /// Show seed from keyring - #[strum_discriminants(strum(message = "🔐Show key of given id from the keyring"))] + #[strum_discriminants(strum(message = "🔐 Show key of given id from the keyring"))] Show(show_key::ShowKeyCommand), /// Remove key from the keyring - #[strum_discriminants(strum(message = "❌Remove key from the keyring"))] + #[strum_discriminants(strum(message = "❌ Remove key from the keyring"))] Remove(remove_key::RemoveKeyCommand), /// Show address - #[strum_discriminants(strum(message = "📌Show address"))] + #[strum_discriminants(strum(message = "📌 Show address"))] ShowAddress(show_address::ShowAddressCommand), } diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index f125a5163..6c21280ee 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -8,10 +8,10 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { /// Select action - #[strum_discriminants(strum(message = "⚙️ Action"))] + #[strum_discriminants(strum(message ="🎬 Action"))] Action(action::CosmosCommands), /// Add, View or Remove key - #[strum_discriminants(strum(message = "🔑Manage keys"))] + #[strum_discriminants(strum(message = "🔑 Manage keys"))] Key(keys::KeyCommands), // TODO: // 1) AddressBook From 77799dcd24e79935d9a44fefb32066181f02df31 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Jan 2024 13:43:29 +0200 Subject: [PATCH 076/135] Validate and re-prompt json/base64 if needed --- .../commands/action/cosmwasm/msg_type/mod.rs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index b4cf87b7f..9d1f4863a 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -1,7 +1,6 @@ use std::str::FromStr; use base64::Engine; -use color_eyre::eyre::Context; use inquire::Select; use strum::{EnumDiscriminants, EnumIter, EnumMessage, IntoEnumIterator}; @@ -59,14 +58,37 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { } } -pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result> { +pub fn msg_bytes(mut message: String, msg_type: MsgType) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { - let data_json = - serde_json::Value::from_str(&message).wrap_err("Data not in JSON format!")?; + let data_json = loop { + if let Ok(val) = serde_json::Value::from_str(&message) { + break val; + } else { + eprintln!("Data not in JSON format!"); + message = inquire::Text::new("Enter message") + // Maybe user need hint + .with_help_message(r#"Valid JSON string (e.g. {"foo": "bar"})"#) + .prompt()?; + } + }; Ok(data_json.to_string().into_bytes()) } - MsgType::Base64Msg => Ok(crate::common::B64.decode(&message)?), + MsgType::Base64Msg => { + let bytes = loop { + match crate::common::B64.decode(&message) { + Ok(decoded) => break decoded, + Err(e) => { + eprintln!("Failed to decode base64 string: {e}"); + message = inquire::Text::new("Enter message") + // Maybe user need hint + .with_help_message("Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==)") + .prompt()?; + } + } + }; + Ok(bytes) + } } } From 5254f943c9a780702a2567038ed78d9ba16b8bc4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Jan 2024 13:44:21 +0200 Subject: [PATCH 077/135] format --- cw-orch-cli/src/commands/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index 6c21280ee..b719dbc13 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -8,7 +8,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { /// Select action - #[strum_discriminants(strum(message ="🎬 Action"))] + #[strum_discriminants(strum(message = "🎬 Action"))] Action(action::CosmosCommands), /// Add, View or Remove key #[strum_discriminants(strum(message = "🔑 Manage keys"))] From d047e64325b275e96c6cf28eaf280714bd71f82b Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 15 Jan 2024 16:25:56 +0200 Subject: [PATCH 078/135] Address book in commands --- cw-orch-cli/Cargo.toml | 2 + .../commands/action/asset/query_cw20/mod.rs | 16 +- .../commands/action/asset/query_native/mod.rs | 14 +- .../commands/action/asset/send_cw20/mod.rs | 17 ++- .../commands/action/asset/send_native/mod.rs | 13 +- .../commands/action/cosmwasm/execute/mod.rs | 9 +- .../commands/action/cosmwasm/query/raw/mod.rs | 9 +- .../action/cosmwasm/query/smart/mod.rs | 10 +- .../commands/action/cw_ownable/accept/mod.rs | 10 +- .../src/commands/action/cw_ownable/get/mod.rs | 10 +- .../src/commands/action/cw_ownable/mod.rs | 8 +- .../action/cw_ownable/renounce/mod.rs | 10 +- .../action/cw_ownable/transfer/mod.rs | 33 ++-- cw-orch-cli/src/commands/mod.rs | 3 + cw-orch-cli/src/types/address_book.rs | 142 ++++++++++++++++++ cw-orch-cli/src/types/chain.rs | 6 +- cw-orch-cli/src/types/mod.rs | 2 + cw-orch-cli/src/types/skippable.rs | 2 +- 18 files changed, 244 insertions(+), 72 deletions(-) create mode 100644 cw-orch-cli/src/types/address_book.rs diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index b0ab3a894..99e9d9c58 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -11,6 +11,8 @@ description = "Command-line tool for managing Cosmos-based interaction." [dependencies] cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.19" } +# TODO: remove when default_state_folder gets exposed in cw-orch +cw-orch-core = { path = "../packages/cw-orch-core", version = "0.19" } # Cosmos cosmwasm-std = { workspace = true } diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index d1fb85d11..c1f7862c3 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -8,16 +8,18 @@ use cosmrs::proto::cosmwasm::wasm::v1::{ query_client::QueryClient, QuerySmartContractStateRequest, }; +use crate::types::CliAddress; + use super::CosmosContext; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryCw20Output)] pub struct QueryCw20Commands { - /// Input cw20 address - cw20_address: String, - /// Address - address: String, + /// Cw20 Address or alias from address-book + cw20_address: CliAddress, + /// Address or alias from address-book + address: CliAddress, } pub struct QueryCw20Output; @@ -28,9 +30,11 @@ impl QueryCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let account_id = scope.address.clone().account_id(chain.chain_info())?; + let cw20_account_id = scope.cw20_address.clone().account_id(chain.chain_info())?; let chain_data: ChainRegistryData = chain.into(); let msg = serde_json::to_vec(&cw20::Cw20QueryMsg::Balance { - address: scope.address.clone(), + address: account_id.to_string(), })?; let rt = Runtime::new()?; @@ -42,7 +46,7 @@ impl QueryCw20Output { let resp = client .smart_contract_state(QuerySmartContractStateRequest { - address: scope.cw20_address.clone(), + address: cw20_account_id.to_string(), query_data: msg, }) .await?; diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index 5bb845060..83d1b5514 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -10,7 +10,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::types::CliSkippable; +use crate::types::{CliAddress, CliSkippable}; use super::CosmosContext; @@ -20,9 +20,8 @@ use super::CosmosContext; pub struct QueryNativeCommands { /// Input denom or leave empty to query all balances denom: CliSkippable, - /// Address - // TODO: Make it Address-bookable - address: String, + /// Address or alias from address-book + address: CliAddress, } pub struct QueryNativeOutput; @@ -35,8 +34,9 @@ impl QueryNativeOutput { let chain = previous_context.chain; let denom = scope.denom.0.clone(); - let chain_data: ChainRegistryData = chain.into(); + let account_id = scope.address.clone().account_id(chain.chain_info())?; + let chain_data: ChainRegistryData = chain.into(); let rt = Runtime::new()?; rt.block_on(async { @@ -46,7 +46,7 @@ impl QueryNativeOutput { if let Some(denom) = denom { let response: QueryBalanceResponse = client .balance(QueryBalanceRequest { - address: scope.address.clone(), + address: account_id.to_string(), denom: denom.clone(), }) .await? @@ -63,7 +63,7 @@ impl QueryNativeOutput { } else { let response: QueryAllBalancesResponse = client .all_balances(QueryAllBalancesRequest { - address: scope.address.clone(), + address: account_id.to_string(), pagination: None, }) .await? diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index ee1354b25..d4d3814f0 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -4,7 +4,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::log::LogOutput; +use crate::{log::LogOutput, types::CliAddress}; use super::CosmosContext; @@ -12,12 +12,12 @@ use super::CosmosContext; #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = SendCw20Output)] pub struct Cw20TransferCommands { - /// Cw20 Address - cw20_address: String, + /// Cw20 Address or alias from address-book + cw20_address: CliAddress, /// Cw20 Amount amount: u128, - /// Recipient - to_address: String, + /// Recipient address or alias from address-book + to_address: CliAddress, /// Signer id signer: String, } @@ -30,9 +30,12 @@ impl SendCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let to_address_account_id = scope.to_address.clone().account_id(chain.chain_info())?; + let cw20_account_id = scope.cw20_address.clone().account_id(chain.chain_info())?; + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { - recipient: scope.to_address.clone(), + recipient: to_address_account_id.to_string(), amount: Uint128::new(scope.amount), }; let msg = serde_json::to_vec(&cw20_msg)?; @@ -47,7 +50,7 @@ impl SendCw20Output { let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: scope.cw20_address.parse()?, + contract: cw20_account_id, msg, funds: vec![], }; diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 83a55e1db..3c80b982e 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -4,7 +4,10 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::{log::LogOutput, types::CliCoins}; +use crate::{ + log::LogOutput, + types::{CliAddress, CliCoins}, +}; use super::CosmosContext; @@ -15,8 +18,8 @@ pub struct SendNativeCommands { #[interactive_clap(skip_default_input_arg)] /// Input coins coins: CliCoins, - /// Recipient - to_address: String, + /// Recipient Address or alias from address-book + to_address: CliAddress, /// Signer id signer: String, } @@ -37,6 +40,8 @@ impl SendNativeOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let to_address = scope.to_address.clone().account_id(chain.chain_info())?; + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins: Vec = (&scope.coins).try_into()?; @@ -51,7 +56,7 @@ impl SendNativeOutput { let transfer_msg = cosmrs::bank::MsgSend { from_address: daemon.sender.pub_addr()?, - to_address: scope.to_address.parse()?, + to_address, amount: coins, }; let resp = daemon.sender.commit_tx(vec![transfer_msg], None).await?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 5f5e35d61..71c2af2ed 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -2,6 +2,7 @@ use color_eyre::eyre::Context; use cw_orch::{daemon::CosmTxResponse, prelude::DaemonAsync, tokio::runtime::Runtime}; use crate::log::LogOutput; +use crate::types::CliAddress; use crate::{commands::action::CosmosContext, types::CliCoins}; use super::msg_type; @@ -11,8 +12,8 @@ use super::msg_type; #[interactive_clap(output_context = ExecuteWasmOutput)] /// Execute contract method pub struct ExecuteContractCommands { - /// Contract address - contract_addr: String, + /// Contract Address or alias from address-book + contract_addr: CliAddress, #[interactive_clap(value_enum)] #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? @@ -48,6 +49,8 @@ impl ExecuteWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope.contract_addr.clone().account_id(chain.chain_info())?; + let seed = crate::common::seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; @@ -62,7 +65,7 @@ impl ExecuteWasmOutput { let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: scope.contract_addr.parse()?, + contract: contract_account_id, msg, funds: coins, }; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index e26781170..373c56608 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -6,14 +6,14 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::commands::action::CosmosContext; +use crate::{commands::action::CosmosContext, types::CliAddress}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryWasmOutput)] pub struct QueryRawCommands { - /// Contract address - contract_addr: String, + /// Contract Address or alias from address-book + contract: CliAddress, // TODO: add base-64 option for binary keys /// Enter key key: String, @@ -27,6 +27,7 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope.contract.clone().account_id(chain.chain_info())?; let chain_data: ChainRegistryData = chain.into(); @@ -38,7 +39,7 @@ impl QueryWasmOutput { let resp = client .raw_contract_state(QueryRawContractStateRequest { - address: scope.contract_addr.clone(), + address: contract_account_id.to_string(), query_data: scope.key.clone().into_bytes(), }) .await?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index b33e137d2..85bb39682 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -6,7 +6,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::commands::action::CosmosContext; +use crate::{commands::action::CosmosContext, types::CliAddress}; use super::super::msg_type; @@ -14,8 +14,8 @@ use super::super::msg_type; #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryWasmOutput)] pub struct QuerySmartCommands { - /// Contract address - contract_addr: String, + /// Contract Address or alias from address-book + contract: CliAddress, #[interactive_clap(value_enum)] #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? @@ -39,6 +39,8 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope.contract.clone().account_id(chain.chain_info())?; + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; let chain_data: ChainRegistryData = chain.into(); @@ -51,7 +53,7 @@ impl QueryWasmOutput { let resp = client .smart_contract_state(QuerySmartContractStateRequest { - address: scope.contract_addr.clone(), + address: contract_account_id.to_string(), query_data: msg, }) .await?; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 5d3635bb7..152350521 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,6 +1,6 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::commands::action::CosmosContext; +use crate::{commands::action::CosmosContext, types::CliAddress}; use super::ContractExecuteMsg; @@ -8,8 +8,8 @@ use super::ContractExecuteMsg; #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = AcceptOwnershipOutput)] pub struct AcceptOwnership { - /// Contract address - contract_addr: String, + /// Contract Address or alias from address-book + contract: CliAddress, /// Signer id // TODO: should be possible to sign it from the seed phrase signer: String, @@ -23,6 +23,8 @@ impl AcceptOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract = scope.contract.clone().account_id(chain.chain_info())?; + let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; @@ -37,7 +39,7 @@ impl AcceptOwnershipOutput { let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: scope.contract_addr.parse()?, + contract, msg, funds: vec![], }; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index f4eab66d2..17ab0c99a 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -7,7 +7,7 @@ use cosmrs::proto::cosmwasm::wasm::v1::{ query_client::QueryClient, QuerySmartContractStateRequest, }; -use crate::commands::action::CosmosContext; +use crate::{commands::action::CosmosContext, types::CliAddress}; use super::ContractQueryMsg; @@ -15,8 +15,8 @@ use super::ContractQueryMsg; #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = GetOwnershipOutput)] pub struct GetOwnership { - /// Contract address - contract_addr: String, + /// Contract Address or alias from address-book + contract: CliAddress, } pub struct GetOwnershipOutput; @@ -27,6 +27,8 @@ impl GetOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope.contract.clone().account_id(chain.chain_info())?; + let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; let chain_data: ChainRegistryData = chain.into(); @@ -38,7 +40,7 @@ impl GetOwnershipOutput { let resp = client .smart_contract_state(QuerySmartContractStateRequest { - address: scope.contract_addr.clone(), + address: contract_account_id.to_string(), query_data: msg, }) .await?; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs index bb6ad9921..f8661784c 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs @@ -35,15 +35,15 @@ pub struct CwOwnableCommands { /// Select cosmwasm action pub enum CwOwnableAction { /// Propose to transfer contract ownership to another address - #[strum_discriminants(strum(message = "💍Propose ownership to another address."))] + #[strum_discriminants(strum(message = "💍 Propose ownership to another address."))] Transfer(transfer::TransferOwnership), /// Accept pending ownership - #[strum_discriminants(strum(message = "✅Accept pending ownership."))] + #[strum_discriminants(strum(message = "✅ Accept pending ownership."))] Accept(accept::AcceptOwnership), // /// Renounce pending ownership - #[strum_discriminants(strum(message = "🚫Renounce pending ownership"))] + #[strum_discriminants(strum(message = "🚫 Renounce pending ownership"))] Renounce(renounce::RenounceOwnership), /// Get current ownership - #[strum_discriminants(strum(message = "❓Get current ownership"))] + #[strum_discriminants(strum(message = "❓ Get current ownership"))] Get(get::GetOwnership), } diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index a213b7b3b..7056fb182 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -1,6 +1,6 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::commands::action::CosmosContext; +use crate::{commands::action::CosmosContext, types::CliAddress}; use super::ContractExecuteMsg; @@ -8,8 +8,8 @@ use super::ContractExecuteMsg; #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = RenounceOwnershipOutput)] pub struct RenounceOwnership { - /// Contract address - contract_addr: String, + /// Contract Address or alias from address-book + contract: CliAddress, /// Signer id // TODO: should be possible to sign it from the seed phrase signer: String, @@ -23,6 +23,8 @@ impl RenounceOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract = scope.contract.clone().account_id(chain.chain_info())?; + let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::RenounceOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; @@ -37,7 +39,7 @@ impl RenounceOwnershipOutput { let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: scope.contract_addr.parse()?, + contract, msg, funds: vec![], }; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index 0d8db334d..e3f2a7470 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -5,7 +5,7 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; use crate::{ commands::action::CosmosContext, common::parse_expiration, - types::{CliExpiration, CliSkippable}, + types::{CliAddress, CliExpiration, CliSkippable}, }; use super::ContractExecuteMsg; @@ -14,18 +14,17 @@ use super::ContractExecuteMsg; #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = TransferOwnershipOutput)] pub struct TransferOwnership { - /// Contract address - contract_addr: String, - /// New owner address - new_owner: String, + /// Contract Address or alias from address-book + contract: CliAddress, + /// New owner Address or alias from address-book + new_owner: CliAddress, /// Expiration #[interactive_clap(skip_default_input_arg)] expiration: CliExpiration, /// Signer id // TODO: should be possible to sign it from the seed phrase signer: String, - /// New owner signer id - #[interactive_clap(skip_default_input_arg)] + /// New owner signer id, leave empty to skip auto-claim new_signer: CliSkippable, } @@ -34,15 +33,6 @@ impl TransferOwnership { let expiration = parse_expiration()?; Ok(Some(CliExpiration(expiration))) } - - fn input_new_signer( - _: &CosmosContext, - ) -> color_eyre::eyre::Result>> { - let new_signer = inquire::Text::new("New signer id") - .with_help_message("Press ESC to skip auto-claim") - .prompt_skippable()?; - Ok(Some(CliSkippable(new_signer))) - } } pub struct TransferOwnershipOutput; @@ -53,6 +43,9 @@ impl TransferOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract = scope.contract.clone().account_id(chain.chain_info())?; + let new_owner = scope.new_owner.clone().account_id(chain.chain_info())?; + let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; let receiver_seed = scope .new_signer @@ -61,7 +54,7 @@ impl TransferOwnershipOutput { .map(crate::common::seed_phrase_for_id) .transpose()?; let action = cw_ownable::Action::TransferOwnership { - new_owner: scope.new_owner.clone(), + new_owner: new_owner.to_string(), expiry: Some(scope.expiration.0), }; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; @@ -76,13 +69,15 @@ impl TransferOwnershipOutput { let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: scope.contract_addr.parse()?, + contract: contract.clone(), msg, funds: vec![], }; let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + // TODO: logging + if let Some(seed) = receiver_seed { let receiver_sender = cw_orch::daemon::sender::Sender::from_mnemonic(&daemon.state, &seed)?; @@ -91,7 +86,7 @@ impl TransferOwnershipOutput { let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender.pub_addr()?, - contract: scope.contract_addr.parse()?, + contract, msg, funds: vec![], }; diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index b719dbc13..642771b08 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -1,6 +1,9 @@ mod action; mod keys; +// TODO: get it upper +pub use action::CosmosContext; + use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs new file mode 100644 index 000000000..8f8be3efc --- /dev/null +++ b/cw-orch-cli/src/types/address_book.rs @@ -0,0 +1,142 @@ +// TODO: Three modes +// - Only alias (will allow making dropdown for addresses) +// - Only raw address +// - Hybrid (current) + +const ADDRESS_BOOK_FILENAME: &str = "address_book.json"; +const CLI_FOLDER: &str = "cli"; + +use std::{ + fs::{File, OpenOptions}, + str::FromStr, +}; + +use cosmrs::AccountId; +use cw_orch::daemon::ChainInfo; +use cw_orch_core::env::default_state_folder; +use serde_json::{json, Value}; + +// TODO: do we save alias on failed tx? +// I think yes, assuming only tx was wrong and address got checked already +// In the worst case user can edit address book +fn get_or_insert_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result { + // open file pointer set read/write permissions to true + // create it if it does not exists + // don't truncate it + let cli_path = default_state_folder()?.join(CLI_FOLDER); + std::fs::create_dir_all(cli_path.as_path())?; + + let address_book_file = cli_path.join(ADDRESS_BOOK_FILENAME); + + let file = OpenOptions::new() + .create(true) + .read(true) + .write(true) + .truncate(false) + .open(address_book_file.as_path())?; + + // return empty json object if file is empty + // return file content if not + let mut json: Value = if file.metadata().unwrap().len().eq(&0) { + json!({}) + } else { + serde_json::from_reader(file).unwrap() + }; + + // check and add chain_id path if it's missing + if json.get(chain_id).is_none() { + json[chain_id] = json!({}); + } + + // add name alias to chain_id path + if let Some(address) = json[chain_id].get(name_alias) { + return if let Some(Ok(account_id)) = address.as_str().map(AccountId::from_str) { + Ok(account_id) + } else { + Err(color_eyre::eyre::eyre!( + "Address Book file is damaged, unable to read address for the provided alias" + )) + }; + } + + let account_id = loop { + let address = inquire::Text::new(&format!( + "Write down the address for the [{name_alias}] alias" + )) + .prompt()?; + if let Ok(account_id) = cosmrs::AccountId::from_str(&address) { + break account_id; + } else { + eprintln!("Failed to parse bech32 address"); + } + }; + + json[chain_id][name_alias] = json!(account_id); + + // write JSON data + // use File::create so we don't append data to the file + // but rather write all (because we have read the data before) + serde_json::to_writer_pretty(File::create(address_book_file).unwrap(), &json).unwrap(); + Ok(account_id) +} + +/// Address or alias to the address +#[derive(Debug, Clone)] +pub enum Address { + Bech32(AccountId), + Alias(String), +} + +impl Address { + // TODO: handle CLI config + pub fn new(bech_or_addr: String, chain_info: &ChainInfo) -> color_eyre::Result { + match cosmrs::AccountId::from_str(&bech_or_addr) { + // Raw address + Ok(account_id) => { + if account_id.prefix() != chain_info.network_info.pub_address_prefix { + // Not recoverable at this point assuming user chose wrong chain + Err(color_eyre::eyre::eyre!( + "Prefix of bech32 address don't match for {}, expected_prefix: {}", + chain_info.chain_id, + chain_info.network_info.pub_address_prefix + )) + } else { + Ok(Address::Bech32(account_id)) + } + } + // Name alias + Err(_) => Ok(Address::Alias(bech_or_addr)), + } + } +} + +#[derive(Debug, Clone, derive_more::AsRef, derive_more::From, derive_more::Into)] +#[as_ref(forward)] +pub struct CliAddress(String); + +impl FromStr for CliAddress { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(Self(s.to_owned())) + } +} + +impl interactive_clap::ToCli for CliAddress { + type CliVariant = CliAddress; +} + +impl CliAddress { + pub fn account_id(self, chain_info: &ChainInfo) -> color_eyre::Result { + match Address::new(self.0, chain_info)? { + Address::Bech32(account_id) => Ok(account_id), + Address::Alias(alias) => get_or_insert_account_id(chain_info.chain_id, &alias), + } + } +} + +impl std::fmt::Display for CliAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/cw-orch-cli/src/types/chain.rs b/cw-orch-cli/src/types/chain.rs index 6ab0ab6f2..24c85bae7 100644 --- a/cw-orch-cli/src/types/chain.rs +++ b/cw-orch-cli/src/types/chain.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use cw_orch::daemon::{networks::SUPPORTED_NETWORKS, ChainRegistryData}; +use cw_orch::daemon::{networks::SUPPORTED_NETWORKS, ChainInfo, ChainRegistryData}; #[derive(Default, Debug, Clone, Copy)] pub struct CliLockedChain(usize); @@ -9,6 +9,10 @@ impl CliLockedChain { pub fn new(index: usize) -> Self { CliLockedChain(index) } + + pub fn chain_info<'a>(&self) -> &ChainInfo<'a> { + &SUPPORTED_NETWORKS[self.0] + } } impl From for ChainRegistryData { diff --git a/cw-orch-cli/src/types/mod.rs b/cw-orch-cli/src/types/mod.rs index 5eefffea9..8a7292a85 100644 --- a/cw-orch-cli/src/types/mod.rs +++ b/cw-orch-cli/src/types/mod.rs @@ -1,9 +1,11 @@ +mod address_book; mod chain; mod coins; mod expiration; mod path_buf; mod skippable; +pub use address_book::CliAddress; pub use chain::CliLockedChain; pub use coins::CliCoins; pub use expiration::CliExpiration; diff --git a/cw-orch-cli/src/types/skippable.rs b/cw-orch-cli/src/types/skippable.rs index 91189e807..8009f5242 100644 --- a/cw-orch-cli/src/types/skippable.rs +++ b/cw-orch-cli/src/types/skippable.rs @@ -1,4 +1,4 @@ -#[derive(Default, PartialEq, Eq, Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct CliSkippable(pub Option); impl std::fmt::Display for CliSkippable { From 250315aac4fbe8d62be46bbff1715a449824c016 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 15 Jan 2024 21:45:48 +0200 Subject: [PATCH 079/135] Address book sub-commands --- cw-orch-cli/src/commands/action/mod.rs | 2 +- .../src/commands/address_book/add_address.rs | 39 +++++ cw-orch-cli/src/commands/address_book/mod.rs | 56 ++++++ .../commands/address_book/remove_address.rs | 37 ++++ .../src/commands/address_book/show_address.rs | 38 +++++ cw-orch-cli/src/commands/mod.rs | 9 +- cw-orch-cli/src/types/address_book.rs | 159 ++++++++++++++++-- cw-orch-cli/src/types/mod.rs | 2 +- 8 files changed, 319 insertions(+), 23 deletions(-) create mode 100644 cw-orch-cli/src/commands/address_book/add_address.rs create mode 100644 cw-orch-cli/src/commands/address_book/mod.rs create mode 100644 cw-orch-cli/src/commands/address_book/remove_address.rs create mode 100644 cw-orch-cli/src/commands/address_book/show_address.rs diff --git a/cw-orch-cli/src/commands/action/mod.rs b/cw-orch-cli/src/commands/action/mod.rs index 5de10fd5d..b0bdfdc21 100644 --- a/cw-orch-cli/src/commands/action/mod.rs +++ b/cw-orch-cli/src/commands/action/mod.rs @@ -45,7 +45,7 @@ impl From for () { #[derive(Clone)] pub struct CosmosContext { - chain: CliLockedChain, + pub chain: CliLockedChain, } impl CosmosContext { diff --git a/cw-orch-cli/src/commands/address_book/add_address.rs b/cw-orch-cli/src/commands/address_book/add_address.rs new file mode 100644 index 000000000..291364735 --- /dev/null +++ b/cw-orch-cli/src/commands/address_book/add_address.rs @@ -0,0 +1,39 @@ +use crate::types::address_book; + +use super::AddresBookContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = AddresBookContext)] +#[interactive_clap(output_context = AddAddressOutput)] +pub struct AddAddress { + /// Alias on AddressBook + alias: String, + /// New Address for the alias + address: String, +} + +pub struct AddAddressOutput; + +impl AddAddressOutput { + fn from_previous_context( + previous_context: AddresBookContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + let maybe_account_id = + address_book::get_account_id(chain.chain_info().chain_id, &scope.alias)?; + + if let Some(account_id) = maybe_account_id { + let confirmed = + inquire::Confirm::new(&format!("Override {}({account_id})?", scope.alias)) + .prompt()?; + if !confirmed { + return Ok(AddAddressOutput); + } + } + + let new_address = address_book::insert_account_id(chain.chain_info().chain_id, &scope.alias, &scope.address)?; + println!("Wrote successfully:\n{}:{}", scope.alias, new_address); + Ok(AddAddressOutput) + } +} diff --git a/cw-orch-cli/src/commands/address_book/mod.rs b/cw-orch-cli/src/commands/address_book/mod.rs new file mode 100644 index 000000000..c7083ec65 --- /dev/null +++ b/cw-orch-cli/src/commands/address_book/mod.rs @@ -0,0 +1,56 @@ +mod add_address; +mod remove_address; +mod show_address; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + +use crate::types::CliLockedChain; + +#[derive(Clone, Debug)] +pub struct AddresBookContext { + pub chain: CliLockedChain, +} + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = AddresBookContext)] +pub struct AddressBookCommands { + #[interactive_clap(skip_default_input_arg)] + chain_id: CliLockedChain, + #[interactive_clap(subcommand)] + key_actions: KeyAction, +} + +impl AddressBookCommands { + fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { + crate::common::select_chain() + } +} + +#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(context = AddresBookContext)] +/// Select key action +pub enum KeyAction { + /// Add or override an Address to your Address Book + #[strum_discriminants(strum(message = "📝 Add or override an Address to your Address Book"))] + Add(add_address::AddAddress), + /// Show address from address book + #[strum_discriminants(strum(message = "📌 Show Address from Address Book"))] + Show(show_address::ShowAddress), + /// Remove an Address from your Address Book + #[strum_discriminants(strum(message = "❌ Remove an address from your address book"))] + Remove(remove_address::RemoveAddress), + // TODO: Fetch cw-orch state +} + +impl AddresBookContext { + fn from_previous_context( + _previous_context: (), + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + Ok(AddresBookContext { + chain: scope.chain_id, + }) + } +} diff --git a/cw-orch-cli/src/commands/address_book/remove_address.rs b/cw-orch-cli/src/commands/address_book/remove_address.rs new file mode 100644 index 000000000..4f08c97a2 --- /dev/null +++ b/cw-orch-cli/src/commands/address_book/remove_address.rs @@ -0,0 +1,37 @@ +use crate::types::address_book; + +use super::AddresBookContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = AddresBookContext)] +#[interactive_clap(output_context = RemoveAddressOutput)] +pub struct RemoveAddress { + /// Address Book Alias for the Address + #[interactive_clap(skip_default_input_arg)] + alias: String, +} + +impl RemoveAddress { + pub fn input_alias(context: &AddresBookContext) -> color_eyre::eyre::Result> { + address_book::select_alias(context.chain.chain_info().chain_id) + } +} + +pub struct RemoveAddressOutput; + +impl RemoveAddressOutput { + fn from_previous_context( + previous_context: AddresBookContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + let removed = + address_book::remove_account_id(chain.chain_info().chain_id, &scope.alias)?; + + match removed { + Some(val) => println!("removed: {val}"), + None => println!("No updates!"), + } + Ok(RemoveAddressOutput) + } +} diff --git a/cw-orch-cli/src/commands/address_book/show_address.rs b/cw-orch-cli/src/commands/address_book/show_address.rs new file mode 100644 index 000000000..6611c00f6 --- /dev/null +++ b/cw-orch-cli/src/commands/address_book/show_address.rs @@ -0,0 +1,38 @@ +use crate::types::address_book::{self, select_alias}; + +use super::AddresBookContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = AddresBookContext)] +#[interactive_clap(output_context = ShowAddressOutput)] +pub struct ShowAddress { + /// Address Book Alias for the Address + #[interactive_clap(skip_default_input_arg)] + alias: String, +} + +impl ShowAddress { + pub fn input_alias(context: &AddresBookContext) -> color_eyre::eyre::Result> { + select_alias(context.chain.chain_info().chain_id) + } +} + +pub struct ShowAddressOutput; + +impl ShowAddressOutput { + fn from_previous_context( + previous_context: AddresBookContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + let maybe_account_id = + address_book::get_account_id(chain.chain_info().chain_id, &scope.alias)?; + + match maybe_account_id { + Some(account_id) => println!("{account_id}"), + None => println!("Not found"), + } + + Ok(ShowAddressOutput) + } +} diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index 642771b08..2d971cb00 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -1,5 +1,6 @@ mod action; mod keys; +mod address_book; // TODO: get it upper pub use action::CosmosContext; @@ -14,9 +15,11 @@ pub enum Commands { #[strum_discriminants(strum(message = "🎬 Action"))] Action(action::CosmosCommands), /// Add, View or Remove key - #[strum_discriminants(strum(message = "🔑 Manage keys"))] + #[strum_discriminants(strum(message = "🔑 Manage Keys"))] Key(keys::KeyCommands), + /// Handle Address Book + #[strum_discriminants(strum(message = "📖 Manage Address Book"))] + AddressBook(address_book::AddressBookCommands), // TODO: - // 1) AddressBook - // 2) Config management + // 1) Config management } diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 8f8be3efc..986722f3c 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -8,6 +8,7 @@ const CLI_FOLDER: &str = "cli"; use std::{ fs::{File, OpenOptions}, + path::PathBuf, str::FromStr, }; @@ -16,31 +17,133 @@ use cw_orch::daemon::ChainInfo; use cw_orch_core::env::default_state_folder; use serde_json::{json, Value}; -// TODO: do we save alias on failed tx? -// I think yes, assuming only tx was wrong and address got checked already -// In the worst case user can edit address book -fn get_or_insert_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result { - // open file pointer set read/write permissions to true - // create it if it does not exists - // don't truncate it +fn cli_path() -> color_eyre::Result { let cli_path = default_state_folder()?.join(CLI_FOLDER); std::fs::create_dir_all(cli_path.as_path())?; + Ok(cli_path) +} + +fn address_book_path() -> color_eyre::Result { + Ok(cli_path()?.join(ADDRESS_BOOK_FILENAME)) +} + +pub fn get_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result> { + let address_book_file = address_book_path()?; + // open file pointer set read permissions to true + let file_result = OpenOptions::new() + .read(true) + .open(address_book_file.as_path()); + let file = match file_result { + Ok(file) => file, + // Unable to read/open file + Err(_) => return Ok(None), + }; + + let json: Value = serde_json::from_reader(file)?; - let address_book_file = cli_path.join(ADDRESS_BOOK_FILENAME); + if let Some(address) = json.get(chain_id).and_then(|chain| chain.get(name_alias)) { + if let Some(Ok(account_id)) = address.as_str().map(AccountId::from_str) { + Ok(Some(account_id)) + } else { + Err(color_eyre::eyre::eyre!( + "Address Book file is damaged. Unable to read address for the [{name_alias}] alias" + )) + } + } else { + Ok(None) + } +} +pub fn insert_account_id( + chain_id: &str, + name_alias: &str, + address: &str, +) -> color_eyre::Result { + // Before doing anything - validate if address is valid + let account_id = AccountId::from_str(address)?; + let address_book_file = address_book_path()?; + // open file pointer set read/write permissions to true + // create it if it does not exists + // don't truncate it let file = OpenOptions::new() + .read(true) + .write(true) .create(true) + .truncate(false) + .open(address_book_file.as_path())?; + // return empty json object if file is empty + // return file content if not + let mut json: Value = if file.metadata()?.len().eq(&0) { + json!({}) + } else { + serde_json::from_reader(file)? + }; + + // check and add chain_id path if it's missing + if json.get(chain_id).is_none() { + json[chain_id] = json!({ + name_alias: account_id + }); + } else { + json[chain_id][name_alias] = json!(account_id); + } + + // write JSON data + // use File::create so we don't append data to the file + // but rather write all (because we have read the data before) + serde_json::to_writer_pretty(File::create(address_book_file)?, &json).unwrap(); + + Ok(account_id) +} + +pub fn remove_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result> { + let address_book_file = address_book_path()?; + // open file pointer set read/write permissions to true + // create it if it does not exists + // don't truncate it + let file = OpenOptions::new() .read(true) .write(true) .truncate(false) .open(address_book_file.as_path())?; + let mut json: serde_json::Map = serde_json::from_reader(file)?; + let aliases_map = match json.get_mut(chain_id) { + Some(aliases) => aliases.as_object_mut().unwrap(), + None => return Ok(None), + }; + let removed = aliases_map.remove(name_alias); + if aliases_map.is_empty() { + // Last alias - remove chain entry + json.remove(chain_id); + } + // write JSON data + // use File::create so we don't append data to the file + // but rather write all (because we have read the data before) + serde_json::to_writer_pretty(File::create(address_book_file)?, &json)?; + Ok(removed) +} + +// TODO: do we save alias on failed tx? +// I think yes, assuming only tx was wrong and address got checked already +// In the worst case user can edit address book +pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result { + let address_book_file = address_book_path()?; + // open file pointer set read/write permissions to true + // create it if it does not exists + // don't truncate it + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(false) + .open(address_book_file.as_path())?; // return empty json object if file is empty // return file content if not - let mut json: Value = if file.metadata().unwrap().len().eq(&0) { + let mut json: Value = if file.metadata()?.len().eq(&0) { json!({}) } else { - serde_json::from_reader(file).unwrap() + serde_json::from_reader(file)? }; // check and add chain_id path if it's missing @@ -48,22 +151,21 @@ fn get_or_insert_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Res json[chain_id] = json!({}); } - // add name alias to chain_id path + // retrieve existing alias if let Some(address) = json[chain_id].get(name_alias) { return if let Some(Ok(account_id)) = address.as_str().map(AccountId::from_str) { Ok(account_id) } else { Err(color_eyre::eyre::eyre!( - "Address Book file is damaged, unable to read address for the provided alias" + "Address Book file is damaged. Unable to read address for the [{name_alias}] alias" )) }; } + // add name alias to chain_id path + let message = format!("Write down the address for the [{name_alias}] alias"); let account_id = loop { - let address = inquire::Text::new(&format!( - "Write down the address for the [{name_alias}] alias" - )) - .prompt()?; + let address = inquire::Text::new(&message).prompt()?; if let Ok(account_id) = cosmrs::AccountId::from_str(&address) { break account_id; } else { @@ -76,10 +178,31 @@ fn get_or_insert_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Res // write JSON data // use File::create so we don't append data to the file // but rather write all (because we have read the data before) - serde_json::to_writer_pretty(File::create(address_book_file).unwrap(), &json).unwrap(); + serde_json::to_writer_pretty(File::create(address_book_file)?, &json).unwrap(); Ok(account_id) } +pub fn select_alias(chain_id: &str) -> color_eyre::eyre::Result> { + let address_book_file = address_book_path()?; + + let file = OpenOptions::new() + .read(true) + .open(address_book_file.as_path()) + .map_err(|_| color_eyre::eyre::eyre!("Must have at least one address in address book"))?; + + let json: Value = serde_json::from_reader(file)?; + let chain_map = json + .as_object() + .ok_or(color_eyre::eyre::eyre!("Address Book file is damaged."))?; + let alias_map = match chain_map.get(chain_id) { + Some(aliases) => aliases.as_object().unwrap(), + None => return Err(color_eyre::eyre::eyre!("Aliases for {chain_id} is empty")), + }; + let aliases: Vec<&String> = alias_map.keys().collect(); + let chosen = inquire::Select::new("Select Address Alias", aliases).prompt()?; + Ok(Some(chosen.to_owned())) +} + /// Address or alias to the address #[derive(Debug, Clone)] pub enum Address { @@ -130,7 +253,7 @@ impl CliAddress { pub fn account_id(self, chain_info: &ChainInfo) -> color_eyre::Result { match Address::new(self.0, chain_info)? { Address::Bech32(account_id) => Ok(account_id), - Address::Alias(alias) => get_or_insert_account_id(chain_info.chain_id, &alias), + Address::Alias(alias) => get_or_prompt_account_id(chain_info.chain_id, &alias), } } } diff --git a/cw-orch-cli/src/types/mod.rs b/cw-orch-cli/src/types/mod.rs index 8a7292a85..2e6b03a4a 100644 --- a/cw-orch-cli/src/types/mod.rs +++ b/cw-orch-cli/src/types/mod.rs @@ -1,4 +1,4 @@ -mod address_book; +pub mod address_book; mod chain; mod coins; mod expiration; From b224f07b5f0334f19a596471a6d841ffb4f31f90 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 15 Jan 2024 21:46:03 +0200 Subject: [PATCH 080/135] format --- cw-orch-cli/src/commands/address_book/add_address.rs | 6 +++++- cw-orch-cli/src/commands/address_book/remove_address.rs | 3 +-- cw-orch-cli/src/commands/mod.rs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/add_address.rs b/cw-orch-cli/src/commands/address_book/add_address.rs index 291364735..37270f6bd 100644 --- a/cw-orch-cli/src/commands/address_book/add_address.rs +++ b/cw-orch-cli/src/commands/address_book/add_address.rs @@ -32,7 +32,11 @@ impl AddAddressOutput { } } - let new_address = address_book::insert_account_id(chain.chain_info().chain_id, &scope.alias, &scope.address)?; + let new_address = address_book::insert_account_id( + chain.chain_info().chain_id, + &scope.alias, + &scope.address, + )?; println!("Wrote successfully:\n{}:{}", scope.alias, new_address); Ok(AddAddressOutput) } diff --git a/cw-orch-cli/src/commands/address_book/remove_address.rs b/cw-orch-cli/src/commands/address_book/remove_address.rs index 4f08c97a2..497f93d5a 100644 --- a/cw-orch-cli/src/commands/address_book/remove_address.rs +++ b/cw-orch-cli/src/commands/address_book/remove_address.rs @@ -25,8 +25,7 @@ impl RemoveAddressOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let removed = - address_book::remove_account_id(chain.chain_info().chain_id, &scope.alias)?; + let removed = address_book::remove_account_id(chain.chain_info().chain_id, &scope.alias)?; match removed { Some(val) => println!("removed: {val}"), diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index 2d971cb00..47e382913 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -1,6 +1,6 @@ mod action; -mod keys; mod address_book; +mod keys; // TODO: get it upper pub use action::CosmosContext; From 2931f323bc18b3fb8cc92545d40265833dd390eb Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 26 Jan 2024 12:08:51 +0200 Subject: [PATCH 081/135] fix cw-plus deps --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4233f5b29..31c5c7fee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ cosmwasm-std = { version = "1.1" } cw-multi-test = { package = "abstract-cw-multi-test", version = "0.20.2", features = [ "cosmwasm_1_4", ] } -cw20 = { git = "https://github.com/AbstractSDK/cw-plus.git" } -cw20-base = { git = "https://github.com/AbstractSDK/cw-plus.git" } +cw20 = { package = "abstract-cw20", git = "https://github.com/AbstractSDK/cw-plus.git" } +cw20-base = { package = "abstract-cw20-base", git = "https://github.com/AbstractSDK/cw-plus.git" } # Test Tube env deps osmosis-test-tube = { version = "21.0.0" } From 2e7292d64f84386d4e38bd9b07e91282fb993b5a Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 26 Jan 2024 12:47:33 +0200 Subject: [PATCH 082/135] merge fixes --- contracts/counter/examples/cli.rs | 2 +- .../src/commands/action/asset/query_cw20/mod.rs | 2 +- .../commands/action/asset/query_native/mod.rs | 2 +- .../commands/action/cosmwasm/query/raw/mod.rs | 2 +- .../commands/action/cosmwasm/query/smart/mod.rs | 2 +- .../src/commands/action/cw_ownable/get/mod.rs | 2 +- .../commands/action/cw_ownable/transfer/mod.rs | 9 +++++---- packages/cw-orch-cli-derive/src/lib.rs | 4 ++-- .../cw-orch-contract-cli/src/contract/mod.rs | 16 ++++++++-------- 9 files changed, 21 insertions(+), 20 deletions(-) diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs index 1f72326e4..6ea14cf63 100644 --- a/contracts/counter/examples/cli.rs +++ b/contracts/counter/examples/cli.rs @@ -8,7 +8,7 @@ pub fn main() -> anyhow::Result<()> { let rt = Runtime::new()?; let chain = Daemon::from_cli(rt.handle())?; - let counter = CounterContract::new("counter_contract", chain); + let counter = CounterContract::new(chain); counter.select_action(Empty {})?; diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index c1f7862c3..a61ca1573 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -41,7 +41,7 @@ impl QueryCw20Output { rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index 83d1b5514..da204605f 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -41,7 +41,7 @@ impl QueryNativeOutput { rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); if let Some(denom) = denom { let response: QueryBalanceResponse = client diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index 373c56608..64641cd36 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -34,7 +34,7 @@ impl QueryWasmOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index 85bb39682..d8c2b0f68 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -48,7 +48,7 @@ impl QueryWasmOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index 17ab0c99a..8067511dc 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -35,7 +35,7 @@ impl GetOwnershipOutput { let rt = Runtime::new()?; rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, &chain_data.chain_id).await?; + GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index e3f2a7470..ce855dec7 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -1,6 +1,7 @@ -use std::rc::Rc; - -use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; +use cw_orch::{ + daemon::{DaemonAsync, Wallet}, + tokio::runtime::Runtime, +}; use crate::{ commands::action::CosmosContext, @@ -81,7 +82,7 @@ impl TransferOwnershipOutput { if let Some(seed) = receiver_seed { let receiver_sender = cw_orch::daemon::sender::Sender::from_mnemonic(&daemon.state, &seed)?; - daemon.set_sender(&Rc::new(receiver_sender)); + daemon.set_sender(&Wallet::new(receiver_sender)); let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs index d7dd8a2a7..4a34eed09 100644 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ b/packages/cw-orch-cli-derive/src/lib.rs @@ -70,7 +70,7 @@ fn parse_fn_derive(input: DeriveInput) -> TokenStream { quote!( #[automatically_derived] impl ::cw_orch_contract_cli::ParseCwMsg for #name { - fn cw_parse(state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { + fn cw_parse(state_interface: &impl ::cw_orch::environment::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { #enum_of_variant_names #display_for_enum_variant_names let options = vec![#(#enum_variants_ident::#idents),*]; @@ -104,7 +104,7 @@ fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_mac let derived_trait_impl = quote!( #[automatically_derived] impl ::cw_orch_contract_cli::ParseCwMsg for #name { - fn cw_parse(_state_interface: &impl ::cw_orch::state::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { + fn cw_parse(_state_interface: &impl ::cw_orch::environment::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { Ok(Self { #(#fields),* }) diff --git a/packages/cw-orch-contract-cli/src/contract/mod.rs b/packages/cw-orch-contract-cli/src/contract/mod.rs index 99b09bc31..ffe1cc168 100644 --- a/packages/cw-orch-contract-cli/src/contract/mod.rs +++ b/packages/cw-orch-contract-cli/src/contract/mod.rs @@ -2,7 +2,7 @@ mod error; use std::{ fmt::{Display, Write}, - rc::Rc, + sync::Arc, }; pub type OrchCliResult = Result; @@ -10,12 +10,12 @@ pub type OrchCliResult = Result; use cosmwasm_std::{Addr, Coin, Empty}; use cw_orch::{ daemon::DaemonState, + environment::ChainState, prelude::{ ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, CwOrchUpload, Daemon, ExecutableContract, InstantiableContract, MigratableContract, QueryableContract, }, - state::ChainState, }; use inquire::{error::InquireResult, ui::RenderConfig, Confirm, CustomType, InquireError, Text}; @@ -94,7 +94,7 @@ where } } - fn instantiate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { + fn instantiate_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { let instantiate_msg = ::InstantiateMsg::cw_parse(state_interface)?; let coins = cw_orch_cli::common::parse_coins()?; @@ -115,7 +115,7 @@ where Ok(()) } - fn execute_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { + fn execute_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; // TODO: figure out a way to make this only with `payable` attribute let coins = cw_orch_cli::common::parse_coins()?; @@ -127,7 +127,7 @@ where Ok(()) } - fn query_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { + fn query_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { let query_msg = ::QueryMsg::cw_parse(state_interface)?; let resp: serde_json::Value = self.query(&query_msg)?; @@ -135,7 +135,7 @@ where Ok(()) } - fn migrate_cli(&self, state_interface: &Rc) -> OrchCliResult<()> { + fn migrate_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; let migrate_msg = ::MigrateMsg::cw_parse(state_interface)?; @@ -151,11 +151,11 @@ pub trait ParseCwMsg where Self: Sized, { - fn cw_parse(state: &impl cw_orch::state::StateInterface) -> OrchCliResult; + fn cw_parse(state: &impl cw_orch::environment::StateInterface) -> OrchCliResult; } impl ParseCwMsg for Empty { - fn cw_parse(_state: &impl cw_orch::state::StateInterface) -> OrchCliResult { + fn cw_parse(_state: &impl cw_orch::environment::StateInterface) -> OrchCliResult { Ok(Empty {}) } } From 31a5ffb60b9169529dd6104845ca577f874a207f Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 26 Jan 2024 13:43:13 +0200 Subject: [PATCH 083/135] cover null query responses --- cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs | 5 +++-- cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index 64641cd36..d77c0049c 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -49,8 +49,9 @@ impl QueryWasmOutput { ) })?; - let parsed_output: serde_json::Value = serde_json::from_slice(&resp.data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); + let parsed_output: Option = serde_json::from_slice(&resp.data)?; + let output = parsed_output.unwrap_or_default(); + println!("{}", serde_json::to_string_pretty(&output)?); Ok(QueryWasmOutput) } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index d8c2b0f68..e03c2a0cd 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -61,8 +61,9 @@ impl QueryWasmOutput { resp.into_inner(), ) })?; - let parsed_output: serde_json::Value = serde_json::from_slice(&resp.data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); + let parsed_output: Option = serde_json::from_slice(&resp.data)?; + let output = parsed_output.unwrap_or_default(); + println!("{}", serde_json::to_string_pretty(&output)?); Ok(QueryWasmOutput) } From 3779a44208ea80e777ef54a39f893e9e745285cf Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 26 Jan 2024 13:43:26 +0200 Subject: [PATCH 084/135] disable back on the first menu --- cw-orch-cli/src/commands/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index 47e382913..bfe91b950 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -9,6 +9,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] +#[interactive_clap(disable_back)] /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { /// Select action From 9932dc65407b6f7fc064490192b848f90b9bcefc Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 26 Jan 2024 15:30:42 +0200 Subject: [PATCH 085/135] restrict empty aliases --- cw-orch-cli/src/types/address_book.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 986722f3c..2a04da65e 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -238,9 +238,13 @@ impl Address { pub struct CliAddress(String); impl FromStr for CliAddress { - type Err = (); + type Err = String; fn from_str(s: &str) -> Result { + if s.is_empty() { + return Err("Address alias be empty".to_owned()); + } + Ok(Self(s.to_owned())) } } From b5e33f1e4c81dbd1ae8f5c036b3550038de6d03d Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 29 Jan 2024 11:26:35 +0200 Subject: [PATCH 086/135] Fix of help messages --- .../src/commands/action/cosmwasm/instantiate/mod.rs | 13 +------------ cw-orch-cli/src/common.rs | 1 - 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 179520742..39f705c1b 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -28,8 +28,7 @@ pub struct InstantiateContractCommands { msg: String, /// Label for the contract label: String, - #[interactive_clap(skip_default_input_arg)] - /// Admin address of the contract + /// Admin address of the contract, leave empty to skip admin admin: CliSkippable, #[interactive_clap(skip_default_input_arg)] /// Input coins @@ -46,16 +45,6 @@ impl InstantiateContractCommands { msg_type::input_msg_type() } - fn input_admin( - _context: &CosmosContext, - ) -> color_eyre::eyre::Result>> { - let val: Option = - inquire::CustomType::new("Input admin address for the contract".to_string().as_str()) - .with_help_message("press Esc to skip admin") - .prompt_skippable()?; - Ok(Some(CliSkippable(val))) - } - fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index 668678938..611650533 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -42,7 +42,6 @@ pub fn parse_coins() -> InquireResult { loop { let coin = inquire::Text::new("Add coin to transaction") .with_placeholder("0ucoin") - .with_help_message("Press ESC to finish adding coins") .prompt()?; if !coin.is_empty() { match coin.parse() { From 3a670a4d1c6e07f54b303f6192605e424f574103 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 9 Feb 2024 14:32:25 +0200 Subject: [PATCH 087/135] WIP: fetch cw_orch --- .../commands/address_book/fetch_cw_orch.rs | 37 +++++++++++++++++++ cw-orch-cli/src/commands/address_book/mod.rs | 5 ++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs new file mode 100644 index 000000000..71a58d6fb --- /dev/null +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -0,0 +1,37 @@ +use crate::types::address_book::{self, select_alias}; + +use super::AddresBookContext; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = AddresBookContext)] +#[interactive_clap(output_context = FetchAddressesOutput)] +pub struct FetchAddresses {} + +#[derive(Debug, strum::EnumDiscriminants, Clone)] +#[strum_discriminants(derive(strum::EnumMessage, strum::EnumIter))] +pub enum DuplicatesStrategy { + #[strum_discriminants(strum(message = "Ask every time"))] + Ask, + #[strum_discriminants(strum(message = "Skip Duplicates"))] + Skip, + #[strum_discriminants(strum(message = "Override Duplicates"))] + Override, +} + +pub struct FetchAddressesOutput; + +impl FetchAddressesOutput { + fn from_previous_context( + previous_context: AddresBookContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let duplicate_strategy = DuplicatesStrategy::Ask; + let state_file = cw_orch_core::env::CwOrchEnvVars::load()?.state_file; + + + let chain = previous_context.chain; + todo!(); + + Ok(FetchAddressesOutput) + } +} diff --git a/cw-orch-cli/src/commands/address_book/mod.rs b/cw-orch-cli/src/commands/address_book/mod.rs index c7083ec65..3d2574770 100644 --- a/cw-orch-cli/src/commands/address_book/mod.rs +++ b/cw-orch-cli/src/commands/address_book/mod.rs @@ -1,6 +1,7 @@ mod add_address; mod remove_address; mod show_address; +mod fetch_cw_orch; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; @@ -41,7 +42,9 @@ pub enum KeyAction { /// Remove an Address from your Address Book #[strum_discriminants(strum(message = "❌ Remove an address from your address book"))] Remove(remove_address::RemoveAddress), - // TODO: Fetch cw-orch state + /// Fetch addresses from cw-orchestrator state file + #[strum_discriminants(strum(message = "🧷 Fetch addresses from cw-orchestrator state file"))] + Fetch(fetch_cw_orch::FetchAddresses) } impl AddresBookContext { From 87c59e1c96afd280b66e3e82a5909bde633159a2 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 9 Feb 2024 19:34:03 +0200 Subject: [PATCH 088/135] cw_orch state fetcher --- .../commands/address_book/fetch_cw_orch.rs | 206 ++++++++++++++++-- 1 file changed, 193 insertions(+), 13 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 0c8f252f5..61af72b23 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -1,37 +1,217 @@ -use crate::types::address_book::{self, select_alias}; +use std::{fs::File, str::FromStr}; + +use cw_orch::daemon::DEFAULT_DEPLOYMENT; +use serde_json::Value; +use strum::IntoEnumIterator; + +const STATE_FILE_DAMAGED_ERROR: &str = "State file is corrupted"; + +use crate::types::{address_book, CliSkippable}; use super::AddresBookContext; +#[derive(Debug, strum::EnumDiscriminants, strum::Display, Clone, clap::ValueEnum)] +#[strum_discriminants(derive(strum::EnumMessage, strum::EnumIter))] +pub enum AliasNameStrategy { + #[strum(serialize = "keep")] + #[strum_discriminants(strum(message = "Keep contract ids as name aliases"))] + /// Keep contract ids as name aliases + Keep, + #[strum(serialize = "rename")] + #[strum_discriminants(strum(message = "Give prompt to rename aliases"))] + /// Give prompt to rename aliases + Rename, +} + +impl interactive_clap::ToCli for AliasNameStrategy { + type CliVariant = AliasNameStrategy; +} + +impl std::fmt::Display for AliasNameStrategyDiscriminants { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AliasNameStrategyDiscriminants::Keep => write!(f, "Keep"), + AliasNameStrategyDiscriminants::Rename => write!(f, "Rename"), + } + } +} + +impl FromStr for AliasNameStrategy { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "keep" => Ok(Self::Keep), + "rename" => Ok(Self::Rename), + _ => Err("AliasNameStrategy: incorrect alias name strategy".to_string()), + } + } +} + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = AddresBookContext)] #[interactive_clap(output_context = FetchAddressesOutput)] -pub struct FetchAddresses {} +pub struct FetchAddresses { + /// Deployment id, leave empty for default + deployment_id: CliSkippable, + #[interactive_clap(value_enum)] + #[interactive_clap(skip_default_input_arg)] + /// Alias names strategy + name_strategy: AliasNameStrategy, +} + +impl FetchAddresses { + fn input_name_strategy( + _context: &AddresBookContext, + ) -> color_eyre::eyre::Result> { + let variants = AliasNameStrategyDiscriminants::iter().collect::>(); + let selected = inquire::Select::new("Select alias names strategy", variants).prompt()?; + match selected { + AliasNameStrategyDiscriminants::Keep => Ok(Some(AliasNameStrategy::Keep)), + AliasNameStrategyDiscriminants::Rename => Ok(Some(AliasNameStrategy::Rename)), + } + } +} -#[derive(Debug, strum::EnumDiscriminants, Clone)] +pub struct FetchAddressesOutput; + +#[derive(Debug, strum::EnumDiscriminants, strum::Display, Clone)] #[strum_discriminants(derive(strum::EnumMessage, strum::EnumIter))] -pub enum DuplicatesStrategy { - #[strum_discriminants(strum(message = "Ask every time"))] - Ask, - #[strum_discriminants(strum(message = "Skip Duplicates"))] +pub enum DuplicateResolve { + #[strum_discriminants(strum(message = "Rename duplicate"))] + Rename, + #[strum_discriminants(strum(message = "Skip duplicate"))] Skip, - #[strum_discriminants(strum(message = "Override Duplicates"))] + #[strum_discriminants(strum(message = "Override duplicate"))] Override, + #[strum_discriminants(strum(message = "Skip all duplicates"))] + SkipAll, + #[strum_discriminants(strum(message = "Override all duplicates"))] + OverrideAll, } -pub struct FetchAddressesOutput; +impl std::fmt::Display for DuplicateResolveDiscriminants { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DuplicateResolveDiscriminants::Rename => write!(f, "Rename"), + DuplicateResolveDiscriminants::Skip => write!(f, "Skip"), + DuplicateResolveDiscriminants::Override => write!(f, "Override"), + DuplicateResolveDiscriminants::SkipAll => write!(f, "Skip All"), + DuplicateResolveDiscriminants::OverrideAll => write!(f, "Override All"), + } + } +} impl FetchAddressesOutput { fn from_previous_context( previous_context: AddresBookContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let duplicate_strategy = DuplicatesStrategy::Ask; - let state_file = cw_orch::environment::CwOrchEnvVars::load()?.state_file; + let state_file = cw_orch::daemon::DaemonState::state_file_path()?; + let deployment_id = scope + .deployment_id + .0 + .as_deref() + .unwrap_or(DEFAULT_DEPLOYMENT); + + let chain_name = previous_context.chain.chain_info().network_info.id; + let chain_id = previous_context.chain.chain_info().chain_id; + + let json = read(&state_file)?; + let Some(chain_state) = json.get(chain_name) else { + return Err(color_eyre::eyre::eyre!("State is empty for {chain_name}")); + }; - let chain = previous_context.chain; - todo!(); + let Some(chain_id_state) = chain_state.get(chain_id) else { + return Err(color_eyre::eyre::eyre!( + "State is empty for {chain_name}.{chain_id}" + )); + }; + let Some(deployment) = chain_id_state.get(deployment_id) else { + return Err(color_eyre::eyre::eyre!( + "State is empty for {chain_name}.{chain_id}.{deployment_id}" + )); + }; + + let contracts = deployment + .as_object() + .ok_or(color_eyre::eyre::eyre!(STATE_FILE_DAMAGED_ERROR))?; + + let mut duplicate_resolve_global = None; + for (contract_id, address) in contracts { + let address = address + .as_str() + .ok_or(color_eyre::eyre::eyre!(STATE_FILE_DAMAGED_ERROR))?; + let mut alias = match scope.name_strategy { + AliasNameStrategy::Keep => contract_id.clone(), + AliasNameStrategy::Rename => inquire::Text::new("Input new contract alias") + .with_initial_value(contract_id) + .prompt()?, + }; + let maybe_address = address_book::get_account_id(chain_id, &alias)?; + + if maybe_address.is_some() { + // Duplicate happened + let duplicate_resolve = if let Some(global_resolved) = &duplicate_resolve_global { + // Check if it's already globally resolved + match global_resolved { + DuplicateResolve::SkipAll => DuplicateResolve::Skip, + DuplicateResolve::OverrideAll => DuplicateResolve::Override, + _ => unreachable!(), + } + } else { + // Or input new one + input_duplicate_resolve(&alias)? + }; + + match duplicate_resolve { + DuplicateResolve::Rename => { + while address_book::get_account_id(chain_id, &alias)?.is_some() { + alias = inquire::Text::new("Rename contract alias") + .with_initial_value(contract_id) + .prompt()?; + } + } + DuplicateResolve::Skip => continue, + DuplicateResolve::SkipAll => { + duplicate_resolve_global = Some(duplicate_resolve); + continue; + } + DuplicateResolve::Override => {} + DuplicateResolve::OverrideAll => { + duplicate_resolve_global = Some(duplicate_resolve); + } + } + } + address_book::insert_account_id(chain_id, &alias, address)?; + } Ok(FetchAddressesOutput) } } + +fn input_duplicate_resolve(original: &str) -> color_eyre::eyre::Result { + let variants = DuplicateResolveDiscriminants::iter().collect::>(); + let selected = inquire::Select::new( + "A duplicate has occurred, what do you prefer to do?", + variants, + ) + .with_help_message(original) + .prompt()?; + let selected = match selected { + DuplicateResolveDiscriminants::Rename => DuplicateResolve::Rename, + DuplicateResolveDiscriminants::Skip => DuplicateResolve::Skip, + DuplicateResolveDiscriminants::Override => DuplicateResolve::Override, + DuplicateResolveDiscriminants::SkipAll => DuplicateResolve::SkipAll, + DuplicateResolveDiscriminants::OverrideAll => DuplicateResolve::OverrideAll, + }; + Ok(selected) +} + +pub fn read(filename: &String) -> color_eyre::Result { + let file = + File::open(filename).unwrap_or_else(|_| panic!("File should be present at {}", filename)); + let json: Value = serde_json::from_reader(file)?; + Ok(json) +} From 51adc2eba98fa846f830f3a3d04fbac1fb7256e0 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 9 Feb 2024 19:34:31 +0200 Subject: [PATCH 089/135] formatting of messages --- cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs | 4 ++-- cw-orch-cli/src/main.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index 9d1f4863a..364fe0d70 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -43,8 +43,8 @@ impl std::fmt::Display for MsgType { impl std::fmt::Display for MsgTypeDiscriminants { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Self::JsonMsg => write!(f, "json-msg"), - Self::Base64Msg => write!(f, "base64-msg"), + Self::JsonMsg => write!(f, "Json Msg"), + Self::Base64Msg => write!(f, "Base64 Msg"), } } } diff --git a/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs index 1b71bac3d..63f8374dd 100644 --- a/cw-orch-cli/src/main.rs +++ b/cw-orch-cli/src/main.rs @@ -1,5 +1,6 @@ use cw_orch_cli::{commands, common}; +use inquire::ui::{Attributes, RenderConfig, StyleSheet}; use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] @@ -11,6 +12,9 @@ pub struct TLCommand { fn main() -> color_eyre::Result<()> { // We don't want to see cw-orch logs during cli std::env::set_var("CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE", "true"); + let mut render_config = RenderConfig::default(); + render_config.prompt = StyleSheet::new().with_attr(Attributes::BOLD); + inquire::set_global_render_config(render_config); // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); From 3d789249b652f9ea7744b594af2c8682d44fdd54 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 9 Feb 2024 19:34:58 +0200 Subject: [PATCH 090/135] Disable skip of expiration --- cw-orch-cli/src/common.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index 611650533..6ce8ca2f0 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -73,8 +73,7 @@ impl ExpirationType { pub fn parse_expiration() -> InquireResult { let locked = inquire::Select::new("Choose expiration type", ExpirationType::VARIANTS.to_vec()) - .prompt_skippable()? - .unwrap_or(ExpirationType::Never); + .prompt()?; let expiration = match locked { ExpirationType::AtHeight => { From 74e395d1134b2953bd9e1cc56a7b71822e9f02af Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 9 Feb 2024 19:41:43 +0200 Subject: [PATCH 091/135] small optimization --- cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 61af72b23..4d977a446 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -150,7 +150,7 @@ impl FetchAddressesOutput { .with_initial_value(contract_id) .prompt()?, }; - let maybe_address = address_book::get_account_id(chain_id, &alias)?; + let mut maybe_address = address_book::get_account_id(chain_id, &alias)?; if maybe_address.is_some() { // Duplicate happened @@ -168,10 +168,11 @@ impl FetchAddressesOutput { match duplicate_resolve { DuplicateResolve::Rename => { - while address_book::get_account_id(chain_id, &alias)?.is_some() { + while maybe_address.is_some() { alias = inquire::Text::new("Rename contract alias") .with_initial_value(contract_id) .prompt()?; + maybe_address = address_book::get_account_id(chain_id, &alias)? } } DuplicateResolve::Skip => continue, From afcc68c9266f4f884ea1d6ae723ced3cf17a34f9 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 12 Feb 2024 17:58:19 +0200 Subject: [PATCH 092/135] few fixes --- .../commands/address_book/fetch_cw_orch.rs | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 4d977a446..358d396e2 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -150,43 +150,52 @@ impl FetchAddressesOutput { .with_initial_value(contract_id) .prompt()?, }; - let mut maybe_address = address_book::get_account_id(chain_id, &alias)?; + let maybe_address = address_book::get_account_id(chain_id, &alias)?; + let is_duplicate = maybe_address.is_some(); - if maybe_address.is_some() { + if is_duplicate { // Duplicate happened - let duplicate_resolve = if let Some(global_resolved) = &duplicate_resolve_global { + let duplicate_resolve = match &duplicate_resolve_global { // Check if it's already globally resolved - match global_resolved { + Some(global_resolved) => match global_resolved { DuplicateResolve::SkipAll => DuplicateResolve::Skip, DuplicateResolve::OverrideAll => DuplicateResolve::Override, _ => unreachable!(), - } - } else { - // Or input new one - input_duplicate_resolve(&alias)? + }, + // Or resolve here + None => input_duplicate_resolve(&alias)?, }; match duplicate_resolve { + // Skip + DuplicateResolve::Skip => (), + DuplicateResolve::SkipAll => { + duplicate_resolve_global = Some(duplicate_resolve); + } + // Rename DuplicateResolve::Rename => { - while maybe_address.is_some() { + loop { alias = inquire::Text::new("Rename contract alias") .with_initial_value(contract_id) .prompt()?; - maybe_address = address_book::get_account_id(chain_id, &alias)? + let is_duplicate = + address_book::get_account_id(chain_id, &alias)?.is_some(); + if !is_duplicate { + break; + } } + address_book::insert_account_id(chain_id, &alias, address)?; } - DuplicateResolve::Skip => continue, - DuplicateResolve::SkipAll => { - duplicate_resolve_global = Some(duplicate_resolve); - continue; + // Override + DuplicateResolve::Override => { + address_book::insert_account_id(chain_id, &alias, address)?; } - DuplicateResolve::Override => {} DuplicateResolve::OverrideAll => { duplicate_resolve_global = Some(duplicate_resolve); + address_book::insert_account_id(chain_id, &alias, address)?; } } } - address_book::insert_account_id(chain_id, &alias, address)?; } Ok(FetchAddressesOutput) } From 8f40b90d7052f61706b61b345843d0c62f491327 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 19 Feb 2024 16:26:52 +0200 Subject: [PATCH 093/135] multiline json --- cw-orch-cli/Cargo.toml | 2 +- .../commands/action/asset/query_cw20/mod.rs | 2 +- .../commands/action/cosmwasm/execute/mod.rs | 5 ++ .../action/cosmwasm/instantiate/mod.rs | 23 ++++++- .../commands/action/cosmwasm/msg_type/mod.rs | 65 ++++++++++++------- .../action/cosmwasm/query/smart/mod.rs | 5 ++ .../src/commands/address_book/add_address.rs | 21 +----- cw-orch-cli/src/types/address_book.rs | 29 +++++++-- 8 files changed, 100 insertions(+), 52 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 7c7e96b20..9697c94fe 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -32,7 +32,7 @@ color-eyre = { version = "0.6" } strum = { version = "0.24", features = ["derive"] } derive_more = "0.99" shell-words = "1.0.0" -inquire = { version = "0.6" } +inquire = { version = "0.6", features = ["editor"] } # Key management keyring = "2.0.5" diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index a61ca1573..bc269c890 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -30,8 +30,8 @@ impl QueryCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let account_id = scope.address.clone().account_id(chain.chain_info())?; let cw20_account_id = scope.cw20_address.clone().account_id(chain.chain_info())?; + let account_id = scope.address.clone().account_id(chain.chain_info())?; let chain_data: ChainRegistryData = chain.into(); let msg = serde_json::to_vec(&cw20::Cw20QueryMsg::Balance { address: account_id.to_string(), diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 71c2af2ed..6592242fa 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -18,6 +18,7 @@ pub struct ExecuteContractCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, + #[interactive_clap(skip_default_input_arg)] /// Enter message msg: String, #[interactive_clap(skip_default_input_arg)] @@ -35,6 +36,10 @@ impl ExecuteContractCommands { msg_type::input_msg_type() } + fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { + msg_type::input_msg() + } + fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 39f705c1b..e3e4ea907 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -8,7 +8,7 @@ use cw_orch::{ use crate::{ commands::action::CosmosContext, log::LogOutput, - types::{CliCoins, CliSkippable}, + types::{address_book, CliCoins, CliSkippable}, }; use super::msg_type; @@ -24,6 +24,7 @@ pub struct InstantiateContractCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, + #[interactive_clap(skip_default_input_arg)] /// Enter message msg: String, /// Label for the contract @@ -45,6 +46,10 @@ impl InstantiateContractCommands { msg_type::input_msg_type() } + fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { + msg_type::input_msg() + } + fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) @@ -87,6 +92,22 @@ impl InstantiateWasmOutput { resp.log(); println!("Address of the instantiated contract: {address}"); + // Maybe save it in Address Book + match inquire::Confirm::new("Would you like to save address in Address Book?").prompt()? { + true => { + let alias = inquire::Text::new("Input new contract alias") + // Use label as default value + .with_initial_value(&scope.label) + .prompt()?; + address_book::try_insert_account_id( + chain.chain_info().chain_id, + &alias, + address.as_str(), + )?; + } + false => (), + }; + Ok(InstantiateWasmOutput) } } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index 364fe0d70..f60d300a8 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -1,6 +1,7 @@ use std::str::FromStr; use base64::Engine; +use color_eyre::eyre::Context; use inquire::Select; use strum::{EnumDiscriminants, EnumIter, EnumMessage, IntoEnumIterator}; @@ -58,36 +59,52 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { } } -pub fn msg_bytes(mut message: String, msg_type: MsgType) -> color_eyre::eyre::Result> { +pub fn input_msg() -> color_eyre::eyre::Result> { + let input = inquire::Text::new("Enter message") + .with_help_message("Leave input empty for EDITOR input later") + .prompt()?; + Ok(Some(input)) +} + +pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { - let data_json = loop { - if let Ok(val) = serde_json::Value::from_str(&message) { - break val; - } else { - eprintln!("Data not in JSON format!"); - message = inquire::Text::new("Enter message") - // Maybe user need hint - .with_help_message(r#"Valid JSON string (e.g. {"foo": "bar"})"#) - .prompt()?; - } + let message = match message.is_empty() { + false => message, + // If message empty - give editor input + true => inquire::Editor::new("Enter message") + .with_help_message(r#"Valid JSON string (e.g. {"foo": "bar"})"#) + .with_predefined_text("{}") + .with_file_extension(".json") + .with_validator(|s: &str| match serde_json::Value::from_str(s) { + Ok(_) => Ok(inquire::validator::Validation::Valid), + Err(_) => Ok(inquire::validator::Validation::Invalid( + inquire::validator::ErrorMessage::Custom( + "Message not in JSON format!".to_owned(), + ), + )), + }) + .with_formatter(&|s| { + serde_json::to_string(&serde_json::Value::from_str(s).unwrap()).unwrap() + }) + .prompt()?, }; - Ok(data_json.to_string().into_bytes()) + let message_json = + serde_json::Value::from_str(&message).wrap_err("Message not in JSON format")?; + + serde_json::to_vec(&message_json).wrap_err("Unexpected error") } MsgType::Base64Msg => { - let bytes = loop { - match crate::common::B64.decode(&message) { - Ok(decoded) => break decoded, - Err(e) => { - eprintln!("Failed to decode base64 string: {e}"); - message = inquire::Text::new("Enter message") - // Maybe user need hint - .with_help_message("Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==)") - .prompt()?; - } - } + let message = match message.is_empty() { + false => message, + true => inquire::Editor::new("Enter") + .with_help_message("Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==)") + .prompt()?, }; - Ok(bytes) + + crate::common::B64 + .decode(&message) + .wrap_err("Failed to decode base64 string") } } } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index e03c2a0cd..5e1b8b7e1 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -20,6 +20,7 @@ pub struct QuerySmartCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, + #[interactive_clap(skip_default_input_arg)] /// Enter message msg: String, } @@ -30,6 +31,10 @@ impl QuerySmartCommands { ) -> color_eyre::eyre::Result> { msg_type::input_msg_type() } + + fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { + msg_type::input_msg() + } } pub struct QueryWasmOutput; diff --git a/cw-orch-cli/src/commands/address_book/add_address.rs b/cw-orch-cli/src/commands/address_book/add_address.rs index 37270f6bd..c6cf68be9 100644 --- a/cw-orch-cli/src/commands/address_book/add_address.rs +++ b/cw-orch-cli/src/commands/address_book/add_address.rs @@ -19,25 +19,8 @@ impl AddAddressOutput { previous_context: AddresBookContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let chain = previous_context.chain; - let maybe_account_id = - address_book::get_account_id(chain.chain_info().chain_id, &scope.alias)?; - - if let Some(account_id) = maybe_account_id { - let confirmed = - inquire::Confirm::new(&format!("Override {}({account_id})?", scope.alias)) - .prompt()?; - if !confirmed { - return Ok(AddAddressOutput); - } - } - - let new_address = address_book::insert_account_id( - chain.chain_info().chain_id, - &scope.alias, - &scope.address, - )?; - println!("Wrote successfully:\n{}:{}", scope.alias, new_address); + let chain_info = previous_context.chain.chain_info(); + address_book::try_insert_account_id(chain_info.chain_id, &scope.alias, &scope.address)?; Ok(AddAddressOutput) } } diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 012ff2bc2..842c97956 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -95,6 +95,26 @@ pub fn insert_account_id( Ok(account_id) } +pub fn try_insert_account_id( + chain_id: &str, + alias: &str, + address: &str, +) -> color_eyre::eyre::Result<()> { + let maybe_account_id = get_account_id(chain_id, alias)?; + + if let Some(account_id) = maybe_account_id { + let confirmed = + inquire::Confirm::new(&format!("Override {}({account_id})?", alias)).prompt()?; + if confirmed { + return Ok(()); + } + } + + let new_address = insert_account_id(chain_id, alias, address)?; + println!("Wrote successfully:\n{}:{}", alias, new_address); + Ok(()) +} + pub fn remove_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result> { let address_book_file = address_book_path()?; // open file pointer set read/write permissions to true @@ -123,9 +143,6 @@ pub fn remove_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result Ok(removed) } -// TODO: do we save alias on failed tx? -// I think yes, assuming only tx was wrong and address got checked already -// In the worst case user can edit address book pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result { let address_book_file = address_book_path()?; // open file pointer set read/write permissions to true @@ -167,9 +184,9 @@ pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre: let address = inquire::Text::new(&message).prompt()?; if let Ok(account_id) = cosmrs::AccountId::from_str(&address) { break account_id; - } else { - eprintln!("Failed to parse bech32 address"); } + + eprintln!("Failed to parse bech32 address"); }; json[chain_id][name_alias] = json!(account_id); @@ -241,7 +258,7 @@ impl FromStr for CliAddress { fn from_str(s: &str) -> Result { if s.is_empty() { - return Err("Address alias be empty".to_owned()); + return Err("Address alias can't be empty".to_owned()); } Ok(Self(s.to_owned())) From c49827bdad8a0d15bee0b5b9c95a3256074e9857 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 19 Feb 2024 17:24:41 +0200 Subject: [PATCH 094/135] enable logs with verbose flag --- cw-orch-cli/Cargo.toml | 7 +++-- cw-orch-cli/src/main.rs | 64 +++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 9697c94fe..697bc592c 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -12,6 +12,9 @@ description = "Command-line tool for managing Cosmos-based interaction." [dependencies] cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.20" } +# Logs +pretty_env_logger = { version = "0.5.0" } + # Cosmos cosmwasm-std = { workspace = true } cw-utils = "1.0.3" @@ -25,8 +28,8 @@ serde = { workspace = true } base64 = { workspace = true } # Interactive clap -interactive-clap = "0.2.4" -interactive-clap-derive = "0.2.4" +interactive-clap = "0.2.8" +interactive-clap-derive = "0.2.8" clap = { version = "4.0.18", features = ["derive"] } color-eyre = { version = "0.6" } strum = { version = "0.24", features = ["derive"] } diff --git a/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs index 63f8374dd..2f82b0008 100644 --- a/cw-orch-cli/src/main.rs +++ b/cw-orch-cli/src/main.rs @@ -4,9 +4,31 @@ use inquire::ui::{Attributes, RenderConfig, StyleSheet}; use interactive_clap::{ResultFromCli, ToCliArgs}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = VerboseEnableContext)] pub struct TLCommand { #[interactive_clap(subcommand)] top_level: commands::Commands, + #[interactive_clap(long)] + verbose: bool, +} + +pub struct VerboseEnableContext; + +impl VerboseEnableContext { + fn from_previous_context( + _previous_context: (), + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + if scope.verbose { + pretty_env_logger::init() + } + Ok(Self) + } +} + +impl From for () { + fn from(_value: VerboseEnableContext) -> Self {} } fn main() -> color_eyre::Result<()> { @@ -19,33 +41,31 @@ fn main() -> color_eyre::Result<()> { let cli_args = TLCommand::parse(); let cw_cli_path = common::get_cw_cli_exec_path(); - loop { - let args = ::from_cli(Some(cli_args.clone()), ()); - match args { - interactive_clap::ResultFromCli::Ok(cli_args) - | ResultFromCli::Cancel(Some(cli_args)) => { + let args = ::from_cli(Some(cli_args.clone()), ()); + + match args { + interactive_clap::ResultFromCli::Ok(cli_args) | ResultFromCli::Cancel(Some(cli_args)) => { + println!( + "Your console command: {}", + shell_words::join(std::iter::once(cw_cli_path).chain(cli_args.to_cli_args())) + ); + Ok(()) + } + interactive_clap::ResultFromCli::Cancel(None) => { + println!("Goodbye!"); + Ok(()) + } + interactive_clap::ResultFromCli::Back => { + unreachable!("TLCommand does not have back option"); + } + interactive_clap::ResultFromCli::Err(cli_args, err) => { + if let Some(cli_args) = cli_args { println!( "Your console command: {}", shell_words::join(std::iter::once(cw_cli_path).chain(cli_args.to_cli_args())) ); - return Ok(()); - } - interactive_clap::ResultFromCli::Cancel(None) => { - println!("Goodbye!"); - return Ok(()); - } - interactive_clap::ResultFromCli::Back => {} - interactive_clap::ResultFromCli::Err(cli_args, err) => { - if let Some(cli_args) = cli_args { - println!( - "Your console command: {}", - shell_words::join( - std::iter::once(cw_cli_path).chain(cli_args.to_cli_args()) - ) - ); - } - return Err(err); } + Err(err) } } } From 270923382aa9e15036634525f5c2fd343354bb90 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 21 Feb 2024 20:43:54 +0200 Subject: [PATCH 095/135] Save signer and signer selector --- .../commands/action/asset/send_cw20/mod.rs | 15 ++- .../commands/action/asset/send_native/mod.rs | 10 +- .../commands/action/cosmwasm/execute/mod.rs | 10 +- .../action/cosmwasm/instantiate/mod.rs | 11 ++- .../src/commands/action/cosmwasm/store/mod.rs | 13 ++- .../commands/action/cw_ownable/accept/mod.rs | 13 ++- .../action/cw_ownable/renounce/mod.rs | 16 ++- .../action/cw_ownable/transfer/mod.rs | 13 ++- cw-orch-cli/src/commands/keys/add_key/mod.rs | 4 +- .../src/commands/keys/remove_key/mod.rs | 11 ++- .../src/commands/keys/show_address/mod.rs | 8 +- cw-orch-cli/src/commands/keys/show_key/mod.rs | 10 +- cw-orch-cli/src/common.rs | 29 +++--- cw-orch-cli/src/types/address_book.rs | 21 ++-- cw-orch-cli/src/types/cli_subdir.rs | 11 +++ cw-orch-cli/src/types/keys.rs | 99 +++++++++++++++++++ cw-orch-cli/src/types/mod.rs | 2 + 17 files changed, 233 insertions(+), 63 deletions(-) create mode 100644 cw-orch-cli/src/types/cli_subdir.rs create mode 100644 cw-orch-cli/src/types/keys.rs diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index d4d3814f0..195e006e2 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -4,7 +4,10 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::{log::LogOutput, types::CliAddress}; +use crate::{ + log::LogOutput, + types::{keys::seed_phrase_for_id, CliAddress}, +}; use super::CosmosContext; @@ -18,10 +21,16 @@ pub struct Cw20TransferCommands { amount: u128, /// Recipient address or alias from address-book to_address: CliAddress, - /// Signer id + #[interactive_clap(skip_default_input_arg)] signer: String, } +impl Cw20TransferCommands { + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } +} + pub struct SendCw20Output; impl SendCw20Output { @@ -33,7 +42,7 @@ impl SendCw20Output { let to_address_account_id = scope.to_address.clone().account_id(chain.chain_info())?; let cw20_account_id = scope.cw20_address.clone().account_id(chain.chain_info())?; - let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let seed = seed_phrase_for_id(&scope.signer)?; let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { recipient: to_address_account_id.to_string(), amount: Uint128::new(scope.amount), diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 3c80b982e..90be30c8e 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -6,7 +6,7 @@ use cw_orch::{ use crate::{ log::LogOutput, - types::{CliAddress, CliCoins}, + types::{keys::seed_phrase_for_id, CliAddress, CliCoins}, }; use super::CosmosContext; @@ -20,7 +20,7 @@ pub struct SendNativeCommands { coins: CliCoins, /// Recipient Address or alias from address-book to_address: CliAddress, - /// Signer id + #[interactive_clap(skip_default_input_arg)] signer: String, } @@ -30,6 +30,10 @@ impl SendNativeCommands { .map(|c| Some(CliCoins(c))) .wrap_err("Bad coins input") } + + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } } pub struct SendNativeOutput; @@ -42,7 +46,7 @@ impl SendNativeOutput { let chain = previous_context.chain; let to_address = scope.to_address.clone().account_id(chain.chain_info())?; - let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let seed = seed_phrase_for_id(&scope.signer)?; let coins: Vec = (&scope.coins).try_into()?; let rt = Runtime::new()?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 6592242fa..48428a97b 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -2,6 +2,7 @@ use color_eyre::eyre::Context; use cw_orch::{daemon::CosmTxResponse, prelude::DaemonAsync, tokio::runtime::Runtime}; use crate::log::LogOutput; +use crate::types::keys::seed_phrase_for_id; use crate::types::CliAddress; use crate::{commands::action::CosmosContext, types::CliCoins}; @@ -24,8 +25,7 @@ pub struct ExecuteContractCommands { #[interactive_clap(skip_default_input_arg)] /// Input coins coins: CliCoins, - /// Signer id - // TODO: should be possible to sign it from the seed phrase + #[interactive_clap(skip_default_input_arg)] signer: String, } @@ -45,6 +45,10 @@ impl ExecuteContractCommands { .map(|c| Some(CliCoins(c))) .wrap_err("Bad coins input") } + + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } } pub struct ExecuteWasmOutput; @@ -56,7 +60,7 @@ impl ExecuteWasmOutput { let chain = previous_context.chain; let contract_account_id = scope.contract_addr.clone().account_id(chain.chain_info())?; - let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let seed = seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index e3e4ea907..e30953e05 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -8,7 +8,7 @@ use cw_orch::{ use crate::{ commands::action::CosmosContext, log::LogOutput, - types::{address_book, CliCoins, CliSkippable}, + types::{address_book, keys::seed_phrase_for_id, CliCoins, CliSkippable}, }; use super::msg_type; @@ -34,8 +34,7 @@ pub struct InstantiateContractCommands { #[interactive_clap(skip_default_input_arg)] /// Input coins coins: CliCoins, - /// Signer id - // TODO: should be possible to sign it from the seed phrase + #[interactive_clap(skip_default_input_arg)] signer: String, } @@ -55,6 +54,10 @@ impl InstantiateContractCommands { .map(|c| Some(CliCoins(c))) .wrap_err("Bad coins input") } + + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } } pub struct InstantiateWasmOutput; @@ -64,7 +67,7 @@ impl InstantiateWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let seed = seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index 4a0dde7c4..7ba1e8dd6 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -5,7 +5,7 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::{commands::action::CosmosContext, log::LogOutput}; +use crate::{commands::action::CosmosContext, log::LogOutput, types::keys::seed_phrase_for_id}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -14,11 +14,16 @@ use crate::{commands::action::CosmosContext, log::LogOutput}; pub struct StoreContractCommands { /// Input path to the wasm wasm_path: crate::types::PathBuf, - /// Signer id - // TODO: should be possible to sign it from the seed phrase + #[interactive_clap(skip_default_input_arg)] signer: String, } +impl StoreContractCommands { + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } +} + pub struct StoreWasmOutput; impl StoreWasmOutput { @@ -27,7 +32,7 @@ impl StoreWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let seed = seed_phrase_for_id(&scope.signer)?; let wasm_byte_code = std::fs::read(&scope.wasm_path).wrap_err(format!( "Failed to open or read the file: {}", scope.wasm_path.0.display() diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 152350521..f7c9f718a 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,6 +1,6 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::{commands::action::CosmosContext, types::CliAddress}; +use crate::{commands::action::CosmosContext, types::{keys::seed_phrase_for_id, CliAddress}}; use super::ContractExecuteMsg; @@ -10,11 +10,16 @@ use super::ContractExecuteMsg; pub struct AcceptOwnership { /// Contract Address or alias from address-book contract: CliAddress, - /// Signer id - // TODO: should be possible to sign it from the seed phrase + #[interactive_clap(skip_default_input_arg)] signer: String, } +impl AcceptOwnership { + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } +} + pub struct AcceptOwnershipOutput; impl AcceptOwnershipOutput { @@ -25,7 +30,7 @@ impl AcceptOwnershipOutput { let chain = previous_context.chain; let contract = scope.contract.clone().account_id(chain.chain_info())?; - let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let sender_seed = seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index 7056fb182..a9a225446 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -1,6 +1,9 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::{commands::action::CosmosContext, types::CliAddress}; +use crate::{ + commands::action::CosmosContext, + types::{keys::seed_phrase_for_id, CliAddress}, +}; use super::ContractExecuteMsg; @@ -10,11 +13,16 @@ use super::ContractExecuteMsg; pub struct RenounceOwnership { /// Contract Address or alias from address-book contract: CliAddress, - /// Signer id - // TODO: should be possible to sign it from the seed phrase + #[interactive_clap(skip_default_input_arg)] signer: String, } +impl RenounceOwnership { + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } +} + pub struct RenounceOwnershipOutput; impl RenounceOwnershipOutput { @@ -25,7 +33,7 @@ impl RenounceOwnershipOutput { let chain = previous_context.chain; let contract = scope.contract.clone().account_id(chain.chain_info())?; - let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let sender_seed = seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::RenounceOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index ce855dec7..779082f02 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -6,7 +6,7 @@ use cw_orch::{ use crate::{ commands::action::CosmosContext, common::parse_expiration, - types::{CliAddress, CliExpiration, CliSkippable}, + types::{keys::seed_phrase_for_id, CliAddress, CliExpiration, CliSkippable}, }; use super::ContractExecuteMsg; @@ -22,8 +22,7 @@ pub struct TransferOwnership { /// Expiration #[interactive_clap(skip_default_input_arg)] expiration: CliExpiration, - /// Signer id - // TODO: should be possible to sign it from the seed phrase + #[interactive_clap(skip_default_input_arg)] signer: String, /// New owner signer id, leave empty to skip auto-claim new_signer: CliSkippable, @@ -34,6 +33,10 @@ impl TransferOwnership { let expiration = parse_expiration()?; Ok(Some(CliExpiration(expiration))) } + + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } } pub struct TransferOwnershipOutput; @@ -47,12 +50,12 @@ impl TransferOwnershipOutput { let contract = scope.contract.clone().account_id(chain.chain_info())?; let new_owner = scope.new_owner.clone().account_id(chain.chain_info())?; - let sender_seed = crate::common::seed_phrase_for_id(&scope.signer)?; + let sender_seed = seed_phrase_for_id(&scope.signer)?; let receiver_seed = scope .new_signer .0 .as_deref() - .map(crate::common::seed_phrase_for_id) + .map(seed_phrase_for_id) .transpose()?; let action = cw_ownable::Action::TransferOwnership { new_owner: new_owner.to_string(), diff --git a/cw-orch-cli/src/commands/keys/add_key/mod.rs b/cw-orch-cli/src/commands/keys/add_key/mod.rs index f4a9e138b..7825a6935 100644 --- a/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -2,14 +2,14 @@ use base64::Engine; use cosmrs::bip32; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::common::{entry_for_seed, B64}; +use crate::common::B64; +use crate::types::keys::entry_for_seed; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = AddKeyContext)] pub struct AddKeyCommand { // TODO: add checker for repetition - // #[interactive_clap(skip_default_input_arg)] /// Id of they key name: String, #[interactive_clap(subcommand)] diff --git a/cw-orch-cli/src/commands/keys/remove_key/mod.rs b/cw-orch-cli/src/commands/keys/remove_key/mod.rs index 847e757a6..ded3e6c19 100644 --- a/cw-orch-cli/src/commands/keys/remove_key/mod.rs +++ b/cw-orch-cli/src/commands/keys/remove_key/mod.rs @@ -1,13 +1,19 @@ -use crate::common::entry_for_seed; +use crate::types::keys::entry_for_seed; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = RemoveKeyOutput)] pub struct RemoveKeyCommand { - /// Id of the key + #[interactive_clap(skip_default_input_arg)] name: String, } +impl RemoveKeyCommand { + fn input_name(_: &()) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } +} + pub struct RemoveKeyOutput; impl RemoveKeyOutput { @@ -17,6 +23,7 @@ impl RemoveKeyOutput { ) -> color_eyre::eyre::Result { let entry = entry_for_seed(&scope.name)?; entry.delete_password()?; + crate::types::keys::remove_entry(&scope.name)?; Ok(RemoveKeyOutput) } } diff --git a/cw-orch-cli/src/commands/keys/show_address/mod.rs b/cw-orch-cli/src/commands/keys/show_address/mod.rs index e720bb187..782ad36ce 100644 --- a/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -1,18 +1,22 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::{common::seed_phrase_for_id, types::CliLockedChain}; +use crate::{types::keys::seed_phrase_for_id, types::CliLockedChain}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = ShowAddressOutput)] pub struct ShowAddressCommand { - /// Id of the key + #[interactive_clap(skip_default_input_arg)] name: String, #[interactive_clap(skip_default_input_arg)] chain_id: CliLockedChain, } impl ShowAddressCommand { + fn input_name(_: &()) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } + fn input_chain_id(_: &()) -> color_eyre::eyre::Result> { crate::common::select_chain() } diff --git a/cw-orch-cli/src/commands/keys/show_key/mod.rs b/cw-orch-cli/src/commands/keys/show_key/mod.rs index 6764c8b7c..fbd3dd1ed 100644 --- a/cw-orch-cli/src/commands/keys/show_key/mod.rs +++ b/cw-orch-cli/src/commands/keys/show_key/mod.rs @@ -1,13 +1,19 @@ -use crate::common::seed_phrase_for_id; +use crate::types::keys::seed_phrase_for_id; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = ShowKeyOutput)] pub struct ShowKeyCommand { - /// Id of the key + #[interactive_clap(skip_default_input_arg)] name: String, } +impl ShowKeyCommand { + fn input_name(_: &()) -> color_eyre::eyre::Result> { + crate::common::select_signer() + } +} + pub struct ShowKeyOutput; impl ShowKeyOutput { diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index 6ce8ca2f0..ff65a4491 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -1,20 +1,7 @@ use crate::types::CliLockedChain; pub use base64::prelude::BASE64_STANDARD as B64; -use base64::Engine; use cw_orch::daemon::networks::SUPPORTED_NETWORKS as NETWORKS; use inquire::{error::InquireResult, InquireError, Select}; -use keyring::Entry; - -pub fn entry_for_seed(name: &str) -> keyring::Result { - Entry::new("cw-cli", name) -} - -pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { - let entry = entry_for_seed(name)?; - let password = entry.get_password()?; - let phrase = String::from_utf8(B64.decode(password)?)?; - Ok(phrase) -} pub fn get_cw_cli_exec_path() -> String { std::env::args().next().unwrap() @@ -37,6 +24,22 @@ pub fn select_chain() -> color_eyre::eyre::Result> { Ok(Some(locked_chain)) } +pub fn select_signer() -> color_eyre::eyre::Result> { + let entries_set_result = crate::types::keys::read_entries(); + let signer_id = match entries_set_result { + // We have a file access and it has at least one signer + Ok(entries_set) if !entries_set.entries.is_empty() => { + let options = entries_set.entries.into_iter().collect(); + Select::new("Select signer id", options) + .with_help_message("Use CLI mode to add signer from previous version") + .prompt()? + } + // We don't have access or it's empty + _ => inquire::Text::new("Signer id").prompt()?, + }; + Ok(Some(signer_id)) +} + pub fn parse_coins() -> InquireResult { let mut coins = cosmwasm_std::Coins::default(); loop { diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 842c97956..376e77af2 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -1,27 +1,23 @@ +use super::cli_subdir::cli_path; + // TODO: Three modes // - Only alias (will allow making dropdown for addresses) // - Only raw address // - Hybrid (current) const ADDRESS_BOOK_FILENAME: &str = "address_book.json"; -const CLI_FOLDER: &str = "cli"; use std::{ fs::{File, OpenOptions}, + io::Seek, path::PathBuf, str::FromStr, }; use cosmrs::AccountId; -use cw_orch::{daemon::ChainInfo, environment::default_state_folder}; +use cw_orch::daemon::ChainInfo; use serde_json::{json, Value}; -fn cli_path() -> color_eyre::Result { - let cli_path = default_state_folder()?.join(CLI_FOLDER); - std::fs::create_dir_all(cli_path.as_path())?; - Ok(cli_path) -} - fn address_book_path() -> color_eyre::Result { Ok(cli_path()?.join(ADDRESS_BOOK_FILENAME)) } @@ -64,7 +60,7 @@ pub fn insert_account_id( // open file pointer set read/write permissions to true // create it if it does not exists // don't truncate it - let file = OpenOptions::new() + let mut file = OpenOptions::new() .read(true) .write(true) .create(true) @@ -75,7 +71,7 @@ pub fn insert_account_id( let mut json: Value = if file.metadata()?.len().eq(&0) { json!({}) } else { - serde_json::from_reader(file)? + serde_json::from_reader(&file)? }; // check and add chain_id path if it's missing @@ -88,9 +84,10 @@ pub fn insert_account_id( } // write JSON data - // use File::create so we don't append data to the file + // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - serde_json::to_writer_pretty(File::create(address_book_file)?, &json).unwrap(); + file.rewind()?; + serde_json::to_writer_pretty(file, &json)?; Ok(account_id) } diff --git a/cw-orch-cli/src/types/cli_subdir.rs b/cw-orch-cli/src/types/cli_subdir.rs new file mode 100644 index 000000000..7f022e49f --- /dev/null +++ b/cw-orch-cli/src/types/cli_subdir.rs @@ -0,0 +1,11 @@ +use std::path::PathBuf; + +use cw_orch::environment::default_state_folder; + +pub const CLI_FOLDER: &str = "cli"; + +pub fn cli_path() -> color_eyre::Result { + let cli_path = default_state_folder()?.join(CLI_FOLDER); + std::fs::create_dir_all(cli_path.as_path())?; + Ok(cli_path) +} diff --git a/cw-orch-cli/src/types/keys.rs b/cw-orch-cli/src/types/keys.rs new file mode 100644 index 000000000..6288265b6 --- /dev/null +++ b/cw-orch-cli/src/types/keys.rs @@ -0,0 +1,99 @@ +use crate::common::B64; + +use base64::Engine; +use keyring::Entry; +use serde::{Deserialize, Serialize}; +use std::{collections::BTreeSet, fs::OpenOptions, io::Seek, path::PathBuf}; + +use super::cli_subdir::cli_path; + +// Should be possible to remove this file in a feature. +// Tracking issue: https://github.com/hwchen/keyring-rs/issues/144 +const ENTRIES_LIST_FILE: &str = "keys_entries.json"; + +#[derive(Default, Serialize, Deserialize)] +pub struct EntriesSet { + pub entries: BTreeSet, +} + +fn entries_list_path() -> color_eyre::Result { + Ok(cli_path()?.join(ENTRIES_LIST_FILE)) +} + +pub fn read_entries() -> color_eyre::Result { + let entries_list_file = entries_list_path()?; + + let file = OpenOptions::new() + .read(true) + .open(entries_list_file.as_path())?; + let entries_set: EntriesSet = serde_json::from_reader(file)?; + Ok(entries_set) +} + +pub fn save_entry_if_required(entry: &str) -> color_eyre::Result<()> { + let entries_list_file = entries_list_path()?; + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(entries_list_file.as_path())?; + let mut entries_set: EntriesSet = if file.metadata()?.len().eq(&0) { + Default::default() + } else { + serde_json::from_reader(&file)? + }; + let need_to_write = entries_set.entries.insert(entry.to_owned()); + + if need_to_write { + // write JSON data + // use File::rewind so we don't append data to the file + // but rather write all (because we have read the data before) + + file.rewind()?; + serde_json::to_writer_pretty(file, &entries_set)?; + } + + Ok(()) +} + +pub fn remove_entry(entry: &str) -> color_eyre::Result<()> { + let entries_list_file = entries_list_path()?; + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(entries_list_file.as_path())?; + let mut entries_set: EntriesSet = if file.metadata()?.len().eq(&0) { + Default::default() + } else { + serde_json::from_reader(&file)? + }; + let need_to_write = entries_set.entries.remove(entry); + + if need_to_write { + // write JSON data + // use File::rewind so we don't append data to the file + // but rather write all (because we have read the data before) + + file.rewind()?; + serde_json::to_writer_pretty(file, &entries_set)?; + } + + Ok(()) +} + + +pub fn entry_for_seed(name: &str) -> keyring::Result { + Entry::new("cw-cli", name) +} + +pub fn seed_phrase_for_id(name: &str) -> color_eyre::Result { + let entry = entry_for_seed(name)?; + let password = entry.get_password()?; + // Found password - so we can save entry + save_entry_if_required(name)?; + let phrase = String::from_utf8(B64.decode(password)?)?; + Ok(phrase) +} diff --git a/cw-orch-cli/src/types/mod.rs b/cw-orch-cli/src/types/mod.rs index 2e6b03a4a..83ee000d6 100644 --- a/cw-orch-cli/src/types/mod.rs +++ b/cw-orch-cli/src/types/mod.rs @@ -1,7 +1,9 @@ pub mod address_book; mod chain; +pub mod cli_subdir; mod coins; mod expiration; +pub mod keys; mod path_buf; mod skippable; From 7d76ab084ae14e82e973f1f4ccc86cdc5b8176b4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 21 Feb 2024 20:49:39 +0200 Subject: [PATCH 096/135] empty-out file before writing --- cw-orch-cli/src/types/address_book.rs | 2 +- cw-orch-cli/src/types/keys.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 376e77af2..e09263ffe 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -86,7 +86,7 @@ pub fn insert_account_id( // write JSON data // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - file.rewind()?; + file.set_len(0)?; serde_json::to_writer_pretty(file, &json)?; Ok(account_id) diff --git a/cw-orch-cli/src/types/keys.rs b/cw-orch-cli/src/types/keys.rs index 6288265b6..3cb0beb80 100644 --- a/cw-orch-cli/src/types/keys.rs +++ b/cw-orch-cli/src/types/keys.rs @@ -50,7 +50,7 @@ pub fn save_entry_if_required(entry: &str) -> color_eyre::Result<()> { // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - file.rewind()?; + file.set_len(0)?; serde_json::to_writer_pretty(file, &entries_set)?; } @@ -77,7 +77,7 @@ pub fn remove_entry(entry: &str) -> color_eyre::Result<()> { // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - file.rewind()?; + file.set_len(0)?; serde_json::to_writer_pretty(file, &entries_set)?; } From e40fa3f9d6a4a5433d3067a241b83b2ae0bea4e6 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 22 Feb 2024 18:44:09 +0200 Subject: [PATCH 097/135] std fs fixes --- .../commands/address_book/fetch_cw_orch.rs | 33 +++++++++---------- cw-orch-cli/src/types/address_book.rs | 6 ++-- cw-orch-cli/src/types/keys.rs | 13 ++++---- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 358d396e2..93f14e60c 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -138,7 +138,6 @@ impl FetchAddressesOutput { let contracts = deployment .as_object() .ok_or(color_eyre::eyre::eyre!(STATE_FILE_DAMAGED_ERROR))?; - let mut duplicate_resolve_global = None; for (contract_id, address) in contracts { let address = address @@ -168,34 +167,32 @@ impl FetchAddressesOutput { match duplicate_resolve { // Skip - DuplicateResolve::Skip => (), + DuplicateResolve::Skip => { + continue; + }, DuplicateResolve::SkipAll => { duplicate_resolve_global = Some(duplicate_resolve); + continue; } // Rename - DuplicateResolve::Rename => { - loop { - alias = inquire::Text::new("Rename contract alias") - .with_initial_value(contract_id) - .prompt()?; - let is_duplicate = - address_book::get_account_id(chain_id, &alias)?.is_some(); - if !is_duplicate { - break; - } + DuplicateResolve::Rename => loop { + alias = inquire::Text::new("Rename contract alias") + .with_initial_value(contract_id) + .prompt()?; + let is_duplicate = + address_book::get_account_id(chain_id, &alias)?.is_some(); + if !is_duplicate { + break; } - address_book::insert_account_id(chain_id, &alias, address)?; - } + }, // Override - DuplicateResolve::Override => { - address_book::insert_account_id(chain_id, &alias, address)?; - } + DuplicateResolve::Override => {} DuplicateResolve::OverrideAll => { duplicate_resolve_global = Some(duplicate_resolve); - address_book::insert_account_id(chain_id, &alias, address)?; } } } + address_book::insert_account_id(chain_id, &alias, address)?; } Ok(FetchAddressesOutput) } diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index e09263ffe..17a0c8400 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -9,7 +9,6 @@ const ADDRESS_BOOK_FILENAME: &str = "address_book.json"; use std::{ fs::{File, OpenOptions}, - io::Seek, path::PathBuf, str::FromStr, }; @@ -60,7 +59,7 @@ pub fn insert_account_id( // open file pointer set read/write permissions to true // create it if it does not exists // don't truncate it - let mut file = OpenOptions::new() + let file = OpenOptions::new() .read(true) .write(true) .create(true) @@ -86,8 +85,7 @@ pub fn insert_account_id( // write JSON data // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - file.set_len(0)?; - serde_json::to_writer_pretty(file, &json)?; + serde_json::to_writer_pretty(File::create(address_book_file)?, &json)?; Ok(account_id) } diff --git a/cw-orch-cli/src/types/keys.rs b/cw-orch-cli/src/types/keys.rs index 3cb0beb80..7c0951b92 100644 --- a/cw-orch-cli/src/types/keys.rs +++ b/cw-orch-cli/src/types/keys.rs @@ -3,7 +3,11 @@ use crate::common::B64; use base64::Engine; use keyring::Entry; use serde::{Deserialize, Serialize}; -use std::{collections::BTreeSet, fs::OpenOptions, io::Seek, path::PathBuf}; +use std::{ + collections::BTreeSet, + fs::{File, OpenOptions}, + path::PathBuf, +}; use super::cli_subdir::cli_path; @@ -50,8 +54,7 @@ pub fn save_entry_if_required(entry: &str) -> color_eyre::Result<()> { // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - file.set_len(0)?; - serde_json::to_writer_pretty(file, &entries_set)?; + serde_json::to_writer_pretty(File::create(entries_list_file)?, &entries_set)?; } Ok(()) @@ -77,14 +80,12 @@ pub fn remove_entry(entry: &str) -> color_eyre::Result<()> { // use File::rewind so we don't append data to the file // but rather write all (because we have read the data before) - file.set_len(0)?; - serde_json::to_writer_pretty(file, &entries_set)?; + serde_json::to_writer_pretty(File::create(entries_list_file)?, &entries_set)?; } Ok(()) } - pub fn entry_for_seed(name: &str) -> keyring::Result { Entry::new("cw-cli", name) } From 1a50604ad91fe2fefb89975c948bd855311fa7d4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 23 Feb 2024 13:17:55 +0200 Subject: [PATCH 098/135] file management quickfix --- .../commands/action/cosmwasm/instantiate/mod.rs | 2 +- .../src/commands/action/cosmwasm/msg_type/mod.rs | 2 +- .../src/commands/action/cw_ownable/accept/mod.rs | 5 ++++- .../src/commands/address_book/fetch_cw_orch.rs | 15 ++++++--------- cw-orch-cli/src/commands/address_book/mod.rs | 4 ++-- cw-orch-cli/src/types/keys.rs | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index e30953e05..4ad57ef4c 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -54,7 +54,7 @@ impl InstantiateContractCommands { .map(|c| Some(CliCoins(c))) .wrap_err("Bad coins input") } - + fn input_signer(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::select_signer() } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index f60d300a8..be82151ac 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -103,7 +103,7 @@ pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result }; crate::common::B64 - .decode(&message) + .decode(message) .wrap_err("Failed to decode base64 string") } } diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index f7c9f718a..686508701 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,6 +1,9 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::{commands::action::CosmosContext, types::{keys::seed_phrase_for_id, CliAddress}}; +use crate::{ + commands::action::CosmosContext, + types::{keys::seed_phrase_for_id, CliAddress}, +}; use super::ContractExecuteMsg; diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 93f14e60c..b2444baec 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -6,7 +6,7 @@ use strum::IntoEnumIterator; const STATE_FILE_DAMAGED_ERROR: &str = "State file is corrupted"; -use crate::types::{address_book, CliSkippable}; +use crate::types::address_book; use super::AddresBookContext; @@ -52,8 +52,9 @@ impl FromStr for AliasNameStrategy { #[interactive_clap(input_context = AddresBookContext)] #[interactive_clap(output_context = FetchAddressesOutput)] pub struct FetchAddresses { - /// Deployment id, leave empty for default - deployment_id: CliSkippable, + #[interactive_clap(long = "deployment-id")] + #[interactive_clap(skip_interactive_input)] + deployment_id: Option, #[interactive_clap(value_enum)] #[interactive_clap(skip_default_input_arg)] /// Alias names strategy @@ -108,11 +109,7 @@ impl FetchAddressesOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let state_file = cw_orch::daemon::DaemonState::state_file_path()?; - let deployment_id = scope - .deployment_id - .0 - .as_deref() - .unwrap_or(DEFAULT_DEPLOYMENT); + let deployment_id = scope.deployment_id.as_deref().unwrap_or(DEFAULT_DEPLOYMENT); let chain_name = previous_context.chain.chain_info().network_info.id; let chain_id = previous_context.chain.chain_info().chain_id; @@ -169,7 +166,7 @@ impl FetchAddressesOutput { // Skip DuplicateResolve::Skip => { continue; - }, + } DuplicateResolve::SkipAll => { duplicate_resolve_global = Some(duplicate_resolve); continue; diff --git a/cw-orch-cli/src/commands/address_book/mod.rs b/cw-orch-cli/src/commands/address_book/mod.rs index 3d2574770..8faa861bb 100644 --- a/cw-orch-cli/src/commands/address_book/mod.rs +++ b/cw-orch-cli/src/commands/address_book/mod.rs @@ -1,7 +1,7 @@ mod add_address; +mod fetch_cw_orch; mod remove_address; mod show_address; -mod fetch_cw_orch; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; @@ -44,7 +44,7 @@ pub enum KeyAction { Remove(remove_address::RemoveAddress), /// Fetch addresses from cw-orchestrator state file #[strum_discriminants(strum(message = "🧷 Fetch addresses from cw-orchestrator state file"))] - Fetch(fetch_cw_orch::FetchAddresses) + Fetch(fetch_cw_orch::FetchAddresses), } impl AddresBookContext { diff --git a/cw-orch-cli/src/types/keys.rs b/cw-orch-cli/src/types/keys.rs index 7c0951b92..98704304b 100644 --- a/cw-orch-cli/src/types/keys.rs +++ b/cw-orch-cli/src/types/keys.rs @@ -37,7 +37,7 @@ pub fn read_entries() -> color_eyre::Result { pub fn save_entry_if_required(entry: &str) -> color_eyre::Result<()> { let entries_list_file = entries_list_path()?; - let mut file = OpenOptions::new() + let file = OpenOptions::new() .read(true) .write(true) .create(true) @@ -63,7 +63,7 @@ pub fn save_entry_if_required(entry: &str) -> color_eyre::Result<()> { pub fn remove_entry(entry: &str) -> color_eyre::Result<()> { let entries_list_file = entries_list_path()?; - let mut file = OpenOptions::new() + let file = OpenOptions::new() .read(true) .write(true) .create(true) From c4133595d15c3fa59ee642caa2cd805f71fe72a6 Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 4 Mar 2024 20:06:08 +0200 Subject: [PATCH 099/135] merge cw orch state option --- cw-orch-cli/src/commands/action/mod.rs | 10 +++-- .../commands/address_book/fetch_cw_orch.rs | 16 +++++--- cw-orch-cli/src/commands/mod.rs | 4 +- cw-orch-cli/src/lib.rs | 37 +++++++++++++++++++ cw-orch-cli/src/main.rs | 36 +++--------------- 5 files changed, 61 insertions(+), 42 deletions(-) diff --git a/cw-orch-cli/src/commands/action/mod.rs b/cw-orch-cli/src/commands/action/mod.rs index b0bdfdc21..1a5938f5f 100644 --- a/cw-orch-cli/src/commands/action/mod.rs +++ b/cw-orch-cli/src/commands/action/mod.rs @@ -4,10 +4,10 @@ mod cw_ownable; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::types::CliLockedChain; +use crate::{types::CliLockedChain, GlobalConfig}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = ())] +#[interactive_clap(input_context = GlobalConfig)] #[interactive_clap(output_context = CosmosContext)] pub struct CosmosCommands { #[interactive_clap(skip_default_input_arg)] @@ -34,7 +34,7 @@ pub enum CosmosAction { } impl CosmosCommands { - fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { + fn input_chain_id(_context: &GlobalConfig) -> color_eyre::eyre::Result> { crate::common::select_chain() } } @@ -46,15 +46,17 @@ impl From for () { #[derive(Clone)] pub struct CosmosContext { pub chain: CliLockedChain, + pub global_config: GlobalConfig, } impl CosmosContext { fn from_previous_context( - _previous_context: (), + previous_context: GlobalConfig, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { Ok(CosmosContext { chain: scope.chain_id, + global_config: previous_context, }) } } diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index b2444baec..3c0ae7b97 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -147,9 +147,9 @@ impl FetchAddressesOutput { .prompt()?, }; let maybe_address = address_book::get_account_id(chain_id, &alias)?; - let is_duplicate = maybe_address.is_some(); - if is_duplicate { + // Duplicate handle + if let Some(current) = maybe_address { // Duplicate happened let duplicate_resolve = match &duplicate_resolve_global { // Check if it's already globally resolved @@ -159,7 +159,7 @@ impl FetchAddressesOutput { _ => unreachable!(), }, // Or resolve here - None => input_duplicate_resolve(&alias)?, + None => input_duplicate_resolve(&alias, ¤t.to_string(), address)?, }; match duplicate_resolve { @@ -195,13 +195,17 @@ impl FetchAddressesOutput { } } -fn input_duplicate_resolve(original: &str) -> color_eyre::eyre::Result { +fn input_duplicate_resolve( + original: &str, + stored: &str, + new: &str, +) -> color_eyre::eyre::Result { let variants = DuplicateResolveDiscriminants::iter().collect::>(); let selected = inquire::Select::new( - "A duplicate has occurred, what do you prefer to do?", + &format!("A duplicate has occurred, what do you prefer to do?"), variants, ) - .with_help_message(original) + .with_help_message(&format!("alias: {original} current: {stored} new: {new}")) .prompt()?; let selected = match selected { DuplicateResolveDiscriminants::Rename => DuplicateResolve::Rename, diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index bfe91b950..fd76bc863 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -2,14 +2,16 @@ mod action; mod address_book; mod keys; -// TODO: get it upper pub use action::CosmosContext; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; +use crate::GlobalConfig; + #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] #[interactive_clap(disable_back)] +#[interactive_clap(context = GlobalConfig)] /// Select one of the options with up-down arrows and press enter to select action pub enum Commands { /// Select action diff --git a/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs index 41fd3e11b..9852b2789 100644 --- a/cw-orch-cli/src/lib.rs +++ b/cw-orch-cli/src/lib.rs @@ -2,3 +2,40 @@ pub mod commands; pub mod common; pub(crate) mod log; pub(crate) mod types; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = ())] +#[interactive_clap(output_context = GlobalConfig)] +pub struct TLCommand { + /// Verbose mode + #[interactive_clap(short, long)] + verbose: bool, + /// Merge cw-orch state file in address-book + #[interactive_clap(short, long)] + cw_orch_merge_state: bool, + #[interactive_clap(subcommand)] + top_level: commands::Commands, +} + +#[derive(Debug, Clone)] +pub struct GlobalConfig { + cw_orch_merged_state: bool, +} + +impl GlobalConfig { + fn from_previous_context( + _previous_context: (), + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + if scope.verbose { + pretty_env_logger::init() + } + Ok(Self { + cw_orch_merged_state: scope.cw_orch_merge_state, + }) + } +} + +impl From for () { + fn from(_value: GlobalConfig) -> Self {} +} diff --git a/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs index 2f82b0008..046f1a180 100644 --- a/cw-orch-cli/src/main.rs +++ b/cw-orch-cli/src/main.rs @@ -1,41 +1,15 @@ -use cw_orch_cli::{commands, common}; +use cw_orch_cli::{common, TLCommand}; use inquire::ui::{Attributes, RenderConfig, StyleSheet}; use interactive_clap::{ResultFromCli, ToCliArgs}; -#[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = ())] -#[interactive_clap(output_context = VerboseEnableContext)] -pub struct TLCommand { - #[interactive_clap(subcommand)] - top_level: commands::Commands, - #[interactive_clap(long)] - verbose: bool, -} - -pub struct VerboseEnableContext; - -impl VerboseEnableContext { - fn from_previous_context( - _previous_context: (), - scope: &::InteractiveClapContextScope, - ) -> color_eyre::eyre::Result { - if scope.verbose { - pretty_env_logger::init() - } - Ok(Self) - } -} - -impl From for () { - fn from(_value: VerboseEnableContext) -> Self {} -} - fn main() -> color_eyre::Result<()> { // We don't want to see cw-orch logs during cli std::env::set_var("CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE", "true"); - let mut render_config = RenderConfig::default(); - render_config.prompt = StyleSheet::new().with_attr(Attributes::BOLD); + let render_config = RenderConfig { + prompt: StyleSheet::new().with_attr(Attributes::BOLD), + ..Default::default() + }; inquire::set_global_render_config(render_config); // TODO: add some configuration like default chain/signer/etc let cli_args = TLCommand::parse(); From f63a03814ae0b87d652cfe3c1b511a305121d1ff Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 11 Mar 2024 16:20:43 +0200 Subject: [PATCH 100/135] update readme script --- cw-orch-cli/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index 700277a57..fb2f5007b 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -23,7 +23,11 @@ This function wraps the CLI and appends its executed action to your current shel ```bash cw-orch-cli() { - command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2 -d':') + command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2- -d':') + if [ "$command" != "cw-orch-cli" ] + then + history -s cw-orch-cli # if you still want to be able `arrow up` to the original command + fi history -s $command } ``` From 1d495086d64eb5f3abd9f8e5aa9c8a0d3ece344b Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 15:23:25 +0200 Subject: [PATCH 101/135] flag to merge cw-orch state --- .../commands/action/asset/query_cw20/mod.rs | 10 +- .../commands/action/asset/query_native/mod.rs | 5 +- .../commands/action/asset/send_cw20/mod.rs | 10 +- .../commands/action/asset/send_native/mod.rs | 5 +- .../commands/action/cosmwasm/execute/mod.rs | 5 +- .../action/cosmwasm/instantiate/mod.rs | 6 +- .../commands/action/cosmwasm/query/raw/mod.rs | 5 +- .../action/cosmwasm/query/smart/mod.rs | 5 +- .../commands/action/cw_ownable/accept/mod.rs | 5 +- .../src/commands/action/cw_ownable/get/mod.rs | 5 +- .../action/cw_ownable/renounce/mod.rs | 5 +- .../action/cw_ownable/transfer/mod.rs | 10 +- .../src/commands/address_book/add_address.rs | 2 +- .../commands/address_book/fetch_cw_orch.rs | 64 ++------- cw-orch-cli/src/commands/address_book/mod.rs | 10 +- .../commands/address_book/remove_address.rs | 2 +- .../src/commands/address_book/show_address.rs | 9 +- cw-orch-cli/src/lib.rs | 17 ++- cw-orch-cli/src/types/address_book.rs | 132 ++++++++++++++++-- 19 files changed, 217 insertions(+), 95 deletions(-) diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index bc269c890..f062e9294 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -30,8 +30,14 @@ impl QueryCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let cw20_account_id = scope.cw20_address.clone().account_id(chain.chain_info())?; - let account_id = scope.address.clone().account_id(chain.chain_info())?; + let cw20_account_id = scope + .cw20_address + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; + let account_id = scope + .address + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let chain_data: ChainRegistryData = chain.into(); let msg = serde_json::to_vec(&cw20::Cw20QueryMsg::Balance { address: account_id.to_string(), diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index da204605f..ac9d75206 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -34,7 +34,10 @@ impl QueryNativeOutput { let chain = previous_context.chain; let denom = scope.denom.0.clone(); - let account_id = scope.address.clone().account_id(chain.chain_info())?; + let account_id = scope + .address + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let chain_data: ChainRegistryData = chain.into(); let rt = Runtime::new()?; diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index 195e006e2..95b4e9c4a 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -39,8 +39,14 @@ impl SendCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let to_address_account_id = scope.to_address.clone().account_id(chain.chain_info())?; - let cw20_account_id = scope.cw20_address.clone().account_id(chain.chain_info())?; + let to_address_account_id = scope + .to_address + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; + let cw20_account_id = scope + .cw20_address + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let seed = seed_phrase_for_id(&scope.signer)?; let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 90be30c8e..a6fbe99e3 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -44,7 +44,10 @@ impl SendNativeOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let to_address = scope.to_address.clone().account_id(chain.chain_info())?; + let to_address = scope + .to_address + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let seed = seed_phrase_for_id(&scope.signer)?; let coins: Vec = (&scope.coins).try_into()?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 48428a97b..45bdea31c 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -58,7 +58,10 @@ impl ExecuteWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract_account_id = scope.contract_addr.clone().account_id(chain.chain_info())?; + let contract_account_id = scope + .contract_addr + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let seed = seed_phrase_for_id(&scope.signer)?; let coins = (&scope.coins).try_into()?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 4ad57ef4c..539a8e567 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -102,11 +102,7 @@ impl InstantiateWasmOutput { // Use label as default value .with_initial_value(&scope.label) .prompt()?; - address_book::try_insert_account_id( - chain.chain_info().chain_id, - &alias, - address.as_str(), - )?; + address_book::try_insert_account_id(chain.chain_info(), &alias, address.as_str())?; } false => (), }; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index d77c0049c..c1ba281e1 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -27,7 +27,10 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract_account_id = scope.contract.clone().account_id(chain.chain_info())?; + let contract_account_id = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let chain_data: ChainRegistryData = chain.into(); diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index 5e1b8b7e1..ab2b83635 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -44,7 +44,10 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract_account_id = scope.contract.clone().account_id(chain.chain_info())?; + let contract_account_id = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 686508701..09ae20271 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -31,7 +31,10 @@ impl AcceptOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract = scope.contract.clone().account_id(chain.chain_info())?; + let contract = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let sender_seed = seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::AcceptOwnership {}; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index 8067511dc..195044cb4 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -27,7 +27,10 @@ impl GetOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract_account_id = scope.contract.clone().account_id(chain.chain_info())?; + let contract_account_id = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; let chain_data: ChainRegistryData = chain.into(); diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index a9a225446..0d46b54b8 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -31,7 +31,10 @@ impl RenounceOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract = scope.contract.clone().account_id(chain.chain_info())?; + let contract = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let sender_seed = seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::RenounceOwnership {}; diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index 779082f02..e47831c84 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -47,8 +47,14 @@ impl TransferOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract = scope.contract.clone().account_id(chain.chain_info())?; - let new_owner = scope.new_owner.clone().account_id(chain.chain_info())?; + let contract = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; + let new_owner = scope + .new_owner + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; let sender_seed = seed_phrase_for_id(&scope.signer)?; let receiver_seed = scope diff --git a/cw-orch-cli/src/commands/address_book/add_address.rs b/cw-orch-cli/src/commands/address_book/add_address.rs index c6cf68be9..2f415cd5e 100644 --- a/cw-orch-cli/src/commands/address_book/add_address.rs +++ b/cw-orch-cli/src/commands/address_book/add_address.rs @@ -20,7 +20,7 @@ impl AddAddressOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain_info = previous_context.chain.chain_info(); - address_book::try_insert_account_id(chain_info.chain_id, &scope.alias, &scope.address)?; + address_book::try_insert_account_id(chain_info, &scope.alias, &scope.address)?; Ok(AddAddressOutput) } } diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 3c0ae7b97..2f633ee98 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -1,12 +1,8 @@ -use std::{fs::File, str::FromStr}; +use std::str::FromStr; -use cw_orch::daemon::DEFAULT_DEPLOYMENT; -use serde_json::Value; use strum::IntoEnumIterator; -const STATE_FILE_DAMAGED_ERROR: &str = "State file is corrupted"; - -use crate::types::address_book; +use crate::types::address_book::{self, cw_orch_state_contracts, CW_ORCH_STATE_FILE_DAMAGED_ERROR}; use super::AddresBookContext; @@ -52,9 +48,6 @@ impl FromStr for AliasNameStrategy { #[interactive_clap(input_context = AddresBookContext)] #[interactive_clap(output_context = FetchAddressesOutput)] pub struct FetchAddresses { - #[interactive_clap(long = "deployment-id")] - #[interactive_clap(skip_interactive_input)] - deployment_id: Option, #[interactive_clap(value_enum)] #[interactive_clap(skip_default_input_arg)] /// Alias names strategy @@ -108,45 +101,22 @@ impl FetchAddressesOutput { previous_context: AddresBookContext, scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { - let state_file = cw_orch::daemon::DaemonState::state_file_path()?; - let deployment_id = scope.deployment_id.as_deref().unwrap_or(DEFAULT_DEPLOYMENT); - - let chain_name = previous_context.chain.chain_info().network_info.id; - let chain_id = previous_context.chain.chain_info().chain_id; - - let json = read(&state_file)?; - - let Some(chain_state) = json.get(chain_name) else { - return Err(color_eyre::eyre::eyre!("State is empty for {chain_name}")); - }; + let chain_info = previous_context.chain.chain_info(); + let contracts = + cw_orch_state_contracts(chain_info, &previous_context.global_config.deployment_id)?; - let Some(chain_id_state) = chain_state.get(chain_id) else { - return Err(color_eyre::eyre::eyre!( - "State is empty for {chain_name}.{chain_id}" - )); - }; - - let Some(deployment) = chain_id_state.get(deployment_id) else { - return Err(color_eyre::eyre::eyre!( - "State is empty for {chain_name}.{chain_id}.{deployment_id}" - )); - }; - - let contracts = deployment - .as_object() - .ok_or(color_eyre::eyre::eyre!(STATE_FILE_DAMAGED_ERROR))?; let mut duplicate_resolve_global = None; for (contract_id, address) in contracts { let address = address .as_str() - .ok_or(color_eyre::eyre::eyre!(STATE_FILE_DAMAGED_ERROR))?; + .ok_or(color_eyre::eyre::eyre!(CW_ORCH_STATE_FILE_DAMAGED_ERROR))?; let mut alias = match scope.name_strategy { AliasNameStrategy::Keep => contract_id.clone(), AliasNameStrategy::Rename => inquire::Text::new("Input new contract alias") - .with_initial_value(contract_id) + .with_initial_value(&contract_id) .prompt()?, }; - let maybe_address = address_book::get_account_id(chain_id, &alias)?; + let maybe_address = address_book::get_account_id_address_book(chain_info, &alias)?; // Duplicate handle if let Some(current) = maybe_address { @@ -159,7 +129,7 @@ impl FetchAddressesOutput { _ => unreachable!(), }, // Or resolve here - None => input_duplicate_resolve(&alias, ¤t.to_string(), address)?, + None => input_duplicate_resolve(&alias, current.as_ref(), address)?, }; match duplicate_resolve { @@ -174,10 +144,11 @@ impl FetchAddressesOutput { // Rename DuplicateResolve::Rename => loop { alias = inquire::Text::new("Rename contract alias") - .with_initial_value(contract_id) + .with_initial_value(&contract_id) .prompt()?; let is_duplicate = - address_book::get_account_id(chain_id, &alias)?.is_some(); + address_book::get_account_id_address_book(chain_info, &alias)? + .is_some(); if !is_duplicate { break; } @@ -189,7 +160,7 @@ impl FetchAddressesOutput { } } } - address_book::insert_account_id(chain_id, &alias, address)?; + address_book::insert_account_id(chain_info.chain_id, &alias, address)?; } Ok(FetchAddressesOutput) } @@ -202,7 +173,7 @@ fn input_duplicate_resolve( ) -> color_eyre::eyre::Result { let variants = DuplicateResolveDiscriminants::iter().collect::>(); let selected = inquire::Select::new( - &format!("A duplicate has occurred, what do you prefer to do?"), + "A duplicate has occurred, what do you prefer to do?", variants, ) .with_help_message(&format!("alias: {original} current: {stored} new: {new}")) @@ -216,10 +187,3 @@ fn input_duplicate_resolve( }; Ok(selected) } - -pub fn read(filename: &String) -> color_eyre::Result { - let file = - File::open(filename).unwrap_or_else(|_| panic!("File should be present at {}", filename)); - let json: Value = serde_json::from_reader(file)?; - Ok(json) -} diff --git a/cw-orch-cli/src/commands/address_book/mod.rs b/cw-orch-cli/src/commands/address_book/mod.rs index 8faa861bb..ad21e208b 100644 --- a/cw-orch-cli/src/commands/address_book/mod.rs +++ b/cw-orch-cli/src/commands/address_book/mod.rs @@ -5,15 +5,16 @@ mod show_address; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::types::CliLockedChain; +use crate::{types::CliLockedChain, GlobalConfig}; #[derive(Clone, Debug)] pub struct AddresBookContext { + pub global_config: GlobalConfig, pub chain: CliLockedChain, } #[derive(Debug, Clone, interactive_clap::InteractiveClap)] -#[interactive_clap(input_context = ())] +#[interactive_clap(input_context = GlobalConfig)] #[interactive_clap(output_context = AddresBookContext)] pub struct AddressBookCommands { #[interactive_clap(skip_default_input_arg)] @@ -23,7 +24,7 @@ pub struct AddressBookCommands { } impl AddressBookCommands { - fn input_chain_id(_context: &()) -> color_eyre::eyre::Result> { + fn input_chain_id(_context: &GlobalConfig) -> color_eyre::eyre::Result> { crate::common::select_chain() } } @@ -49,10 +50,11 @@ pub enum KeyAction { impl AddresBookContext { fn from_previous_context( - _previous_context: (), + previous_context: GlobalConfig, scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { Ok(AddresBookContext { + global_config: previous_context, chain: scope.chain_id, }) } diff --git a/cw-orch-cli/src/commands/address_book/remove_address.rs b/cw-orch-cli/src/commands/address_book/remove_address.rs index 497f93d5a..c1a8f39b7 100644 --- a/cw-orch-cli/src/commands/address_book/remove_address.rs +++ b/cw-orch-cli/src/commands/address_book/remove_address.rs @@ -13,7 +13,7 @@ pub struct RemoveAddress { impl RemoveAddress { pub fn input_alias(context: &AddresBookContext) -> color_eyre::eyre::Result> { - address_book::select_alias(context.chain.chain_info().chain_id) + address_book::select_alias(context.chain.chain_info(), &context.global_config) } } diff --git a/cw-orch-cli/src/commands/address_book/show_address.rs b/cw-orch-cli/src/commands/address_book/show_address.rs index 6611c00f6..005787392 100644 --- a/cw-orch-cli/src/commands/address_book/show_address.rs +++ b/cw-orch-cli/src/commands/address_book/show_address.rs @@ -13,7 +13,7 @@ pub struct ShowAddress { impl ShowAddress { pub fn input_alias(context: &AddresBookContext) -> color_eyre::eyre::Result> { - select_alias(context.chain.chain_info().chain_id) + select_alias(context.chain.chain_info(), &context.global_config) } } @@ -25,8 +25,11 @@ impl ShowAddressOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let maybe_account_id = - address_book::get_account_id(chain.chain_info().chain_id, &scope.alias)?; + let maybe_account_id = address_book::get_account_id( + chain.chain_info(), + &previous_context.global_config, + &scope.alias, + )?; match maybe_account_id { Some(account_id) => println!("{account_id}"), diff --git a/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs index 9852b2789..68c7b3b09 100644 --- a/cw-orch-cli/src/lib.rs +++ b/cw-orch-cli/src/lib.rs @@ -3,6 +3,8 @@ pub mod common; pub(crate) mod log; pub(crate) mod types; +use cw_orch::daemon::DEFAULT_DEPLOYMENT; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = GlobalConfig)] @@ -12,14 +14,19 @@ pub struct TLCommand { verbose: bool, /// Merge cw-orch state file in address-book #[interactive_clap(short, long)] - cw_orch_merge_state: bool, + merge_cw_orch_state: bool, + /// Deployment id, that will be used for merging cw_orch_state + #[interactive_clap(long = "deployment-id")] + #[interactive_clap(skip_interactive_input)] + deployment_id: Option, #[interactive_clap(subcommand)] top_level: commands::Commands, } #[derive(Debug, Clone)] pub struct GlobalConfig { - cw_orch_merged_state: bool, + merge_cw_orch_state: bool, + deployment_id: String, } impl GlobalConfig { @@ -31,7 +38,11 @@ impl GlobalConfig { pretty_env_logger::init() } Ok(Self { - cw_orch_merged_state: scope.cw_orch_merge_state, + merge_cw_orch_state: scope.merge_cw_orch_state, + deployment_id: scope + .deployment_id + .clone() + .unwrap_or(DEFAULT_DEPLOYMENT.to_owned()), }) } } diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 17a0c8400..7fd5e39bc 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -1,3 +1,5 @@ +use crate::GlobalConfig; + use super::cli_subdir::cli_path; // TODO: Three modes @@ -6,6 +8,7 @@ use super::cli_subdir::cli_path; // - Hybrid (current) const ADDRESS_BOOK_FILENAME: &str = "address_book.json"; +pub const CW_ORCH_STATE_FILE_DAMAGED_ERROR: &str = "cw-orch state file is corrupted"; use std::{ fs::{File, OpenOptions}, @@ -13,6 +16,7 @@ use std::{ str::FromStr, }; +use color_eyre::eyre::Context; use cosmrs::AccountId; use cw_orch::daemon::ChainInfo; use serde_json::{json, Value}; @@ -21,8 +25,13 @@ fn address_book_path() -> color_eyre::Result { Ok(cli_path()?.join(ADDRESS_BOOK_FILENAME)) } -pub fn get_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result> { +/// Get account id only from address-book +pub fn get_account_id_address_book( + chain: &ChainInfo, + name_alias: &str, +) -> color_eyre::Result> { let address_book_file = address_book_path()?; + let chain_id = chain.chain_id; // open file pointer set read permissions to true let file_result = OpenOptions::new() .read(true) @@ -48,6 +57,30 @@ pub fn get_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result color_eyre::Result> { + let account_id_address_book = get_account_id_address_book(chain, name_alias)?; + // If address found in address book or cw-orch state merge disabled - no need to read cw orch state + if account_id_address_book.is_some() || !global_config.merge_cw_orch_state { + return Ok(account_id_address_book); + } + // Try to load cw orch state contract + let cw_orch_contracts = cw_orch_state_contracts(chain, &global_config.deployment_id)?; + if let Some(contract) = cw_orch_contracts.get(name_alias) { + let contract_addr = contract + .as_str() + .ok_or(color_eyre::eyre::eyre!(CW_ORCH_STATE_FILE_DAMAGED_ERROR))?; + // Ignore parse error, cw-orch can store non bech32 addresses which CLI does not support + Ok(AccountId::from_str(contract_addr).ok()) + } else { + Ok(None) + } +} + pub fn insert_account_id( chain_id: &str, name_alias: &str, @@ -91,11 +124,11 @@ pub fn insert_account_id( } pub fn try_insert_account_id( - chain_id: &str, + chain: &ChainInfo, alias: &str, address: &str, ) -> color_eyre::eyre::Result<()> { - let maybe_account_id = get_account_id(chain_id, alias)?; + let maybe_account_id = get_account_id_address_book(chain, alias)?; if let Some(account_id) = maybe_account_id { let confirmed = @@ -105,7 +138,7 @@ pub fn try_insert_account_id( } } - let new_address = insert_account_id(chain_id, alias, address)?; + let new_address = insert_account_id(chain.chain_id, alias, address)?; println!("Wrote successfully:\n{}:{}", alias, new_address); Ok(()) } @@ -138,7 +171,11 @@ pub fn remove_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result Ok(removed) } -pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre::Result { +pub fn get_or_prompt_account_id( + chain: &ChainInfo, + global_config: &GlobalConfig, + name_alias: &str, +) -> color_eyre::Result { let address_book_file = address_book_path()?; // open file pointer set read/write permissions to true // create it if it does not exists @@ -158,12 +195,12 @@ pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre: }; // check and add chain_id path if it's missing - if json.get(chain_id).is_none() { - json[chain_id] = json!({}); + if json.get(chain.chain_id).is_none() { + json[chain.chain_id] = json!({}); } - // retrieve existing alias - if let Some(address) = json[chain_id].get(name_alias) { + // Try to retrieve existing alias + if let Some(address) = json[chain.chain_id].get(name_alias) { return if let Some(Ok(account_id)) = address.as_str().map(AccountId::from_str) { Ok(account_id) } else { @@ -172,6 +209,19 @@ pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre: )) }; } + // Try to retrieve from cw-orch state if merging enabled + if global_config.merge_cw_orch_state { + let cw_orch_contracts = cw_orch_state_contracts(chain, &global_config.deployment_id)?; + if let Some(contract) = cw_orch_contracts.get(name_alias) { + let contract_addr = contract + .as_str() + .ok_or(color_eyre::eyre::eyre!(CW_ORCH_STATE_FILE_DAMAGED_ERROR))?; + // Ignore parse error, cw-orch can store non bech32 addresses which CLI does not support + if let Ok(account_id) = AccountId::from_str(contract_addr) { + return Ok(account_id); + } + } + } // add name alias to chain_id path let message = format!("Write down the address for the [{name_alias}] alias"); @@ -184,7 +234,7 @@ pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre: eprintln!("Failed to parse bech32 address"); }; - json[chain_id][name_alias] = json!(account_id); + json[chain.chain_id][name_alias] = json!(account_id); // write JSON data // use File::create so we don't append data to the file @@ -193,7 +243,18 @@ pub fn get_or_prompt_account_id(chain_id: &str, name_alias: &str) -> color_eyre: Ok(account_id) } -pub fn select_alias(chain_id: &str) -> color_eyre::eyre::Result> { +pub fn select_alias( + chain_info: &ChainInfo, + global_config: &GlobalConfig, +) -> color_eyre::eyre::Result> { + let chain_id = chain_info.chain_id; + + let cw_orch_contracts = if global_config.merge_cw_orch_state { + cw_orch_state_contracts(chain_info, &global_config.deployment_id)? + } else { + Default::default() + }; + let address_book_file = address_book_path()?; let file = OpenOptions::new() @@ -209,11 +270,50 @@ pub fn select_alias(chain_id: &str) -> color_eyre::eyre::Result> Some(aliases) => aliases.as_object().unwrap(), None => return Err(color_eyre::eyre::eyre!("Aliases for {chain_id} is empty")), }; - let aliases: Vec<&String> = alias_map.keys().collect(); + let aliases: Vec<_> = alias_map.keys().chain(cw_orch_contracts.keys()).collect(); let chosen = inquire::Select::new("Select Address Alias", aliases).prompt()?; Ok(Some(chosen.to_owned())) } +fn read_cw_orch_state() -> color_eyre::Result { + let state_file = cw_orch::daemon::DaemonState::state_file_path()?; + + let file = + File::open(&state_file).context(format!("File should be present at {state_file}"))?; + let json: Value = serde_json::from_reader(file)?; + Ok(json) +} + +pub fn cw_orch_state_contracts( + chain: &ChainInfo, + deployment_id: &str, +) -> color_eyre::Result> { + let chain_name = chain.network_info.id; + let chain_id = chain.chain_id; + + let json = read_cw_orch_state()?; + + let Some(chain_state) = json.get(chain_name) else { + return Err(color_eyre::eyre::eyre!("State is empty for {chain_name}")); + }; + + let Some(chain_id_state) = chain_state.get(chain_id) else { + return Err(color_eyre::eyre::eyre!( + "State is empty for {chain_name}.{chain_id}" + )); + }; + + let Some(deployment) = chain_id_state.get(deployment_id) else { + return Err(color_eyre::eyre::eyre!( + "State is empty for {chain_name}.{chain_id}.{deployment_id}" + )); + }; + + let contracts = deployment + .as_object() + .ok_or(color_eyre::eyre::eyre!(CW_ORCH_STATE_FILE_DAMAGED_ERROR))?; + Ok(contracts.clone()) +} /// Address or alias to the address #[derive(Debug, Clone)] pub enum Address { @@ -265,10 +365,14 @@ impl interactive_clap::ToCli for CliAddress { } impl CliAddress { - pub fn account_id(self, chain_info: &ChainInfo) -> color_eyre::Result { + pub fn account_id( + self, + chain_info: &ChainInfo, + global_config: &GlobalConfig, + ) -> color_eyre::Result { match Address::new(self.0, chain_info)? { Address::Bech32(account_id) => Ok(account_id), - Address::Alias(alias) => get_or_prompt_account_id(chain_info.chain_id, &alias), + Address::Alias(alias) => get_or_prompt_account_id(chain_info, global_config, &alias), } } } From 58f99bba051439ee6bbf5a8cb63a247f7e1a1bee Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 15:26:03 +0200 Subject: [PATCH 102/135] fix clippy --- cw-orch-daemon/src/channel.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cw-orch-daemon/src/channel.rs b/cw-orch-daemon/src/channel.rs index d71e22a65..fbe12ed17 100644 --- a/cw-orch-daemon/src/channel.rs +++ b/cw-orch-daemon/src/channel.rs @@ -101,7 +101,7 @@ mod tests { #[tokio::test] async fn no_connection() { let mut chain = cw_orch_daemon::networks::LOCAL_JUNO; - let grpcs = &vec!["https://127.0.0.1:99999"]; + let grpcs = &["https://127.0.0.1:99999"]; chain.grpc_urls = grpcs; let build_res = DaemonAsync::builder() @@ -120,7 +120,7 @@ mod tests { #[tokio::test] async fn network_grpcs_list_is_empty() { let mut chain = cw_orch_daemon::networks::LOCAL_JUNO; - let grpcs: &Vec<&str> = &vec![]; + let grpcs: &[&str] = &[]; chain.grpc_urls = grpcs; let build_res = DaemonAsync::builder() From ae71ced84a851e366efe9ad7fdce337d59a443a9 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 15:50:09 +0200 Subject: [PATCH 103/135] add file message input --- cw-orch-cli/Cargo.toml | 4 +-- .../commands/action/cosmwasm/execute/mod.rs | 2 +- .../action/cosmwasm/instantiate/mod.rs | 2 +- .../commands/action/cosmwasm/msg_type/mod.rs | 29 ++++++++++++++----- .../action/cosmwasm/query/smart/mod.rs | 2 +- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 697bc592c..1987512c9 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-orch-cli" -version = "0.1.0" +version = "0.2.0" authors = ["Buckram "] edition.workspace = true license.workspace = true @@ -10,7 +10,7 @@ description = "Command-line tool for managing Cosmos-based interaction." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.20" } +cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.21" } # Logs pretty_env_logger = { version = "0.5.0" } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 45bdea31c..64df91f7f 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -37,7 +37,7 @@ impl ExecuteContractCommands { } fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { - msg_type::input_msg() + msg_type::input_msg_or_filename() } fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 539a8e567..06864f193 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -46,7 +46,7 @@ impl InstantiateContractCommands { } fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { - msg_type::input_msg() + msg_type::input_msg_or_filename() } fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index be82151ac..e912f57b9 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -15,6 +15,9 @@ pub enum MsgType { #[strum_discriminants(strum(message = "base64 message"))] /// Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==) Base64Msg, + /// Read from a file (e.g. file.json) + #[strum_discriminants(strum(message = "File message"))] + FileMsg, } impl interactive_clap::ToCli for MsgType { @@ -27,6 +30,7 @@ impl std::str::FromStr for MsgType { match s { "json-msg" => Ok(Self::JsonMsg), "base64-msg" => Ok(Self::Base64Msg), + "file-msg" => Ok(Self::FileMsg), _ => Err("MsgType: incorrect message type".to_string()), } } @@ -37,6 +41,7 @@ impl std::fmt::Display for MsgType { match self { Self::JsonMsg => write!(f, "json-msg"), Self::Base64Msg => write!(f, "base64-msg"), + Self::FileMsg => write!(f, "file-msg"), } } } @@ -46,6 +51,7 @@ impl std::fmt::Display for MsgTypeDiscriminants { match self { Self::JsonMsg => write!(f, "Json Msg"), Self::Base64Msg => write!(f, "Base64 Msg"), + Self::FileMsg => write!(f, "File Msg"), } } } @@ -56,21 +62,22 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { match selected { MsgTypeDiscriminants::JsonMsg => Ok(Some(MsgType::JsonMsg)), MsgTypeDiscriminants::Base64Msg => Ok(Some(MsgType::Base64Msg)), + MsgTypeDiscriminants::FileMsg => Ok(Some(MsgType::FileMsg)), } } -pub fn input_msg() -> color_eyre::eyre::Result> { - let input = inquire::Text::new("Enter message") - .with_help_message("Leave input empty for EDITOR input later") +pub fn input_msg_or_filename() -> color_eyre::eyre::Result> { + let input = inquire::Text::new("Enter message or filename") + .with_help_message("Leave non-file message input empty for EDITOR input later") .prompt()?; Ok(Some(input)) } -pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result> { +pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { - let message = match message.is_empty() { - false => message, + let message = match message_or_file.is_empty() { + false => message_or_file, // If message empty - give editor input true => inquire::Editor::new("Enter message") .with_help_message(r#"Valid JSON string (e.g. {"foo": "bar"})"#) @@ -95,8 +102,8 @@ pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result serde_json::to_vec(&message_json).wrap_err("Unexpected error") } MsgType::Base64Msg => { - let message = match message.is_empty() { - false => message, + let message = match message_or_file.is_empty() { + false => message_or_file, true => inquire::Editor::new("Enter") .with_help_message("Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==)") .prompt()?, @@ -106,6 +113,12 @@ pub fn msg_bytes(message: String, msg_type: MsgType) -> color_eyre::eyre::Result .decode(message) .wrap_err("Failed to decode base64 string") } + MsgType::FileMsg => { + let file_path = std::path::PathBuf::from(message_or_file); + let msg_bytes = + std::fs::read(file_path.as_path()).wrap_err("Failed to read a message file")?; + Ok(msg_bytes) + } } } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index ab2b83635..52c20e14e 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -33,7 +33,7 @@ impl QuerySmartCommands { } fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { - msg_type::input_msg() + msg_type::input_msg_or_filename() } } pub struct QueryWasmOutput; From 47d9060ededbc4f071fc076efcb1b314826c404d Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 16:14:30 +0200 Subject: [PATCH 104/135] few fixes --- cw-orch-cli/src/commands/address_book/show_address.rs | 2 +- cw-orch-cli/src/lib.rs | 6 +++--- cw-orch-cli/src/types/address_book.rs | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/show_address.rs b/cw-orch-cli/src/commands/address_book/show_address.rs index 005787392..2ddff4ead 100644 --- a/cw-orch-cli/src/commands/address_book/show_address.rs +++ b/cw-orch-cli/src/commands/address_book/show_address.rs @@ -33,7 +33,7 @@ impl ShowAddressOutput { match maybe_account_id { Some(account_id) => println!("{account_id}"), - None => println!("Not found"), + None => println!("Address not found"), } Ok(ShowAddressOutput) diff --git a/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs index 68c7b3b09..d773cff85 100644 --- a/cw-orch-cli/src/lib.rs +++ b/cw-orch-cli/src/lib.rs @@ -10,13 +10,13 @@ use cw_orch::daemon::DEFAULT_DEPLOYMENT; #[interactive_clap(output_context = GlobalConfig)] pub struct TLCommand { /// Verbose mode - #[interactive_clap(short, long)] + #[interactive_clap(short, long, global = true)] verbose: bool, /// Merge cw-orch state file in address-book - #[interactive_clap(short, long)] + #[interactive_clap(short, long, global = true)] merge_cw_orch_state: bool, /// Deployment id, that will be used for merging cw_orch_state - #[interactive_clap(long = "deployment-id")] + #[interactive_clap(long = "deployment-id", global = true)] #[interactive_clap(skip_interactive_input)] deployment_id: Option, #[interactive_clap(subcommand)] diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 7fd5e39bc..b6b276a9f 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -267,10 +267,13 @@ pub fn select_alias( .as_object() .ok_or(color_eyre::eyre::eyre!("Address Book file is damaged."))?; let alias_map = match chain_map.get(chain_id) { - Some(aliases) => aliases.as_object().unwrap(), - None => return Err(color_eyre::eyre::eyre!("Aliases for {chain_id} is empty")), + Some(aliases) => aliases.as_object().unwrap().clone(), + None => Default::default(), }; let aliases: Vec<_> = alias_map.keys().chain(cw_orch_contracts.keys()).collect(); + if aliases.is_empty() { + return Err(color_eyre::eyre::eyre!("Aliases for {chain_id} is empty")); + } let chosen = inquire::Select::new("Select Address Alias", aliases).prompt()?; Ok(Some(chosen.to_owned())) } From 7058a875901ffdbcf85e46f640cddda46b85a893 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 16:14:42 +0200 Subject: [PATCH 105/135] readme update --- cw-orch-cli/README.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index fb2f5007b..dd086e20e 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -2,13 +2,15 @@ The CosmWasm Orch CLI is a tool designed to facilitate the development, deployment, and interaction with CosmWasm smart contracts on Cosmos blockchains. It enables developers to create, test, and manage contracts using the interactive CLI and easily deploy them onto supported Cosmos networks. -# Installation +## Installation + +### Prerequisites -## Prerequisites - Rust - OpenSSL +- Access to keyring -## Cargo +### Cargo ```bash cargo install cw-orch-cli @@ -16,7 +18,7 @@ cargo install cw-orch-cli ### Add last command to the shell history (Optional) -If Cw Orch CLI ran in interactive mode it's executed command will **not** be appended to your shell history. This means you will not be able to `arrow up` to get the last command and tweak it to your liking. +If Cw Orch CLI ran in interactive mode it's executed command will **not** be appended to your shell history. This means you will not be able to `arrow up` to get the last command and tweak it to your liking. To solve this you can add the function below to your `~/.bashrc` or similar. This function wraps the CLI and appends its executed action to your current shell history, enabling you to retrieve it from the history. @@ -26,7 +28,7 @@ cw-orch-cli() { command=$(command cw-orch-cli "$@" | tee /dev/tty | grep 'Your console command' | cut -f2- -d':') if [ "$command" != "cw-orch-cli" ] then - history -s cw-orch-cli # if you still want to be able `arrow up` to the original command + history -s cw-orch-cli "$@" # if you still want to be able `arrow up` to the original command fi history -s $command } @@ -42,6 +44,12 @@ In interactive mode the CLI will guide you through complex tasks by reducing the The interactive mode will prompt you for new information when needed as you go through the process of creating, testing, and deploying a contract. +Example: + +```bash +cw-orch-cli --verbose +``` + ### Non-interactive mode You can utilize the non-interactive mode for scripting, automated operations, and tweaking of the interactive mode's commands. Often you'll find yourself using the interactive mode to get the command you need, and then debug it with the non-interactive mode. @@ -51,3 +59,11 @@ Example: ```bash cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms6q698938k529q3shmfl90 contract_info ``` + +### Global optional arguments + +- `-v` or `--verbose` - enable verbose mode, this will log actions from cw-orch daemon executions that corresponds to your `RUST_LOG` level +- -m, --merge-cw-orch-state - merge cw-orch state file(`STATE_FILE` [cw-orch env variable]) with address-book (address book have higher priority) +- --deployment-id - cw-orch state deployment-id, defaults to "default" + +[cw-orch env variable]: ../docs/src/contracts/env-variable.md \ No newline at end of file From 21aea2cea4b9a2cd5a78478e0ef50c08c8d039b4 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 16:21:40 +0200 Subject: [PATCH 106/135] move contract cli --- contracts/counter/Cargo.toml | 5 +- contracts/counter/examples/cli.rs | 16 -- contracts/counter/src/interface.rs | 13 - contracts/counter/src/msg.rs | 4 - packages/cw-orch-cli-derive/Cargo.toml | 18 -- packages/cw-orch-cli-derive/src/lib.rs | 115 --------- packages/cw-orch-contract-cli/Cargo.toml | 21 -- .../src/contract/error.rs | 15 -- .../cw-orch-contract-cli/src/contract/mod.rs | 236 ------------------ .../cw-orch-contract-cli/src/daemon/mod.rs | 21 -- packages/cw-orch-contract-cli/src/lib.rs | 18 -- 11 files changed, 1 insertion(+), 481 deletions(-) delete mode 100644 contracts/counter/examples/cli.rs delete mode 100644 packages/cw-orch-cli-derive/Cargo.toml delete mode 100644 packages/cw-orch-cli-derive/src/lib.rs delete mode 100644 packages/cw-orch-contract-cli/Cargo.toml delete mode 100644 packages/cw-orch-contract-cli/src/contract/error.rs delete mode 100644 packages/cw-orch-contract-cli/src/contract/mod.rs delete mode 100644 packages/cw-orch-contract-cli/src/daemon/mod.rs delete mode 100644 packages/cw-orch-contract-cli/src/lib.rs diff --git a/contracts/counter/Cargo.toml b/contracts/counter/Cargo.toml index 89cf0434b..d59e07ae4 100644 --- a/contracts/counter/Cargo.toml +++ b/contracts/counter/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib", "rlib"] [features] default = ["export"] export = [] -interface = ["dep:cw-orch", "dep:cw-orch-contract-cli"] +interface = ["dep:cw-orch"] [dependencies] cosmwasm-std = { workspace = true } @@ -25,13 +25,10 @@ serde = { workspace = true } serde_json = "1.0.79" cw-orch = { path = "../../cw-orch", optional = true, features = ["daemon"] } -cw-orch-contract-cli = { path = "../../packages/cw-orch-contract-cli", optional = true } - [dev-dependencies] counter-contract = { path = ".", features = ["interface"] } # Deps for deployment dotenv = { version = "0.15.0" } pretty_env_logger = { version = "0.5.0" } cw-orch = { path = "../../cw-orch", features = ["daemon", "osmosis-test-tube"] } -cw-orch-contract-cli = { path = "../../packages/cw-orch-contract-cli" } anyhow.workspace = true diff --git a/contracts/counter/examples/cli.rs b/contracts/counter/examples/cli.rs deleted file mode 100644 index 6ea14cf63..000000000 --- a/contracts/counter/examples/cli.rs +++ /dev/null @@ -1,16 +0,0 @@ -use cosmwasm_std::Empty; -use counter_contract::CounterContract; -use cw_orch::{anyhow, prelude::Daemon, tokio::runtime::Runtime}; -use cw_orch_contract_cli::{ContractCli, DaemonFromCli}; - -pub fn main() -> anyhow::Result<()> { - dotenv::dotenv().ok(); - - let rt = Runtime::new()?; - let chain = Daemon::from_cli(rt.handle())?; - let counter = CounterContract::new(chain); - - counter.select_action(Empty {})?; - - Ok(()) -} diff --git a/contracts/counter/src/interface.rs b/contracts/counter/src/interface.rs index 065347c7a..47f275aed 100644 --- a/contracts/counter/src/interface.rs +++ b/contracts/counter/src/interface.rs @@ -61,16 +61,3 @@ impl CounterContract { } } // ANCHOR_END: daemon - -// ANCHOR: cli -use cw_orch_contract_cli::OrchCliResult; - -impl cw_orch_contract_cli::CwCliAddons for CounterContract { - fn addons(&mut self, _context: Empty) -> OrchCliResult<()> - where - Self: cw_orch::prelude::ContractInstance, - { - Ok(()) - } -} -// ANCHOR_END diff --git a/contracts/counter/src/msg.rs b/contracts/counter/src/msg.rs index fb2932bca..be60654aa 100644 --- a/contracts/counter/src/msg.rs +++ b/contracts/counter/src/msg.rs @@ -4,7 +4,6 @@ use cosmwasm_schema::{cw_serde, QueryResponses}; #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] /// Instantiate method for counter pub struct InstantiateMsg { /// Initial count @@ -13,7 +12,6 @@ pub struct InstantiateMsg { // ANCHOR: exec_msg #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] #[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))] // Function generation /// Execute methods for counter pub enum ExecuteMsg { @@ -29,7 +27,6 @@ pub enum ExecuteMsg { // ANCHOR: query_msg #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] #[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] // Function generation #[derive(QueryResponses)] /// Query methods for counter @@ -49,7 +46,6 @@ pub struct GetCountResponse { // ANCHOR_END: query_msg #[cw_serde] -#[cfg_attr(feature = "interface", derive(cw_orch_contract_cli::ParseCwMsg))] /// Migrate message for count contract pub struct MigrateMsg { /// Your favorite type of tea diff --git a/packages/cw-orch-cli-derive/Cargo.toml b/packages/cw-orch-cli-derive/Cargo.toml deleted file mode 100644 index 47ffadb24..000000000 --- a/packages/cw-orch-cli-derive/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "cw-orch-cli-derive" -version = "0.13.3" -authors = { workspace = true } -edition = { workspace = true } -license = { workspace = true } -repository = { workspace = true } -description = "Derive macro for generating cli interface." - -[lib] -proc-macro = true - -[dependencies] -quote = "1" -proc-macro2 = "1" -syn = { version = "1", features = ["full", "extra-traits", "visit-mut"] } -convert_case = "0.6.0" -interactive-clap = "0.2.4" diff --git a/packages/cw-orch-cli-derive/src/lib.rs b/packages/cw-orch-cli-derive/src/lib.rs deleted file mode 100644 index 4a34eed09..000000000 --- a/packages/cw-orch-cli-derive/src/lib.rs +++ /dev/null @@ -1,115 +0,0 @@ -use convert_case::Casing; -use proc_macro::TokenStream; -extern crate proc_macro; -use quote::quote; -use syn::{parse_macro_input, DeriveInput, Fields, FieldsNamed}; - -#[proc_macro_derive(ParseCwMsg)] -pub fn derive_parse_cw_message(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - parse_fn_derive(input) -} - -fn parse_fn_derive(input: DeriveInput) -> TokenStream { - let name = &input.ident; - match &input.data { - syn::Data::Struct(data) => impl_parse_for_struct(&data.fields, name), - syn::Data::Enum(data) => { - let idents: Vec<_> = data.variants.iter().map(|variant| &variant.ident).collect(); - // Generate helper enum - let enum_variants_ident = - proc_macro2::Ident::new(&format!("{name}Variants"), name.span()); - let enum_of_variant_names = quote!( - enum #enum_variants_ident { - #(#idents),* - } - ); - let display_for_enum_variant_names = idents.iter().map(|&ident| { - let name = ident.to_string().to_case(convert_case::Case::Snake); - quote!( - #enum_variants_ident::#ident => f.pad(#name) - ) - }); - let display_for_enum_variant_names = quote!( - impl ::std::fmt::Display for #enum_variants_ident { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - match self { - #(#display_for_enum_variant_names),* - } - } - } - ); - - let variants_as_structs = data.variants.iter().map(|variant| { - let struct_name = &variant.ident; - let syn::Fields::Named(FieldsNamed { - named, - .. - }) = &variant.fields else { - unimplemented!() - }; - let field_names = named.into_iter().map(|a| a.ident.clone().unwrap()); - let field_names = quote!({#(#field_names),*}); - let into_enum = quote!( - impl From<#struct_name> for #name { - fn from(val: #struct_name) -> Self { - let #struct_name #field_names = val; - #name::#struct_name #field_names - } - } - ); - let fields = &variant.fields; - let sub_derived_trait_impl = impl_parse_for_struct(fields, struct_name); - quote!( - struct #struct_name - #fields - #into_enum - #sub_derived_trait_impl - ) - }); - quote!( - #[automatically_derived] - impl ::cw_orch_contract_cli::ParseCwMsg for #name { - fn cw_parse(state_interface: &impl ::cw_orch::environment::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { - #enum_of_variant_names - #display_for_enum_variant_names - let options = vec![#(#enum_variants_ident::#idents),*]; - let variant = ::cw_orch_contract_cli::select_msg(options)?; - #(#variants_as_structs)* - let msg = match variant { - #(#enum_variants_ident::#idents => #idents::cw_parse(state_interface)?.into()),* - }; - Ok(msg) - } - } - ) - } - syn::Data::Union(_) => { - unimplemented!() - } - } - .into() -} - -fn impl_parse_for_struct(fields: &Fields, name: &proc_macro2::Ident) -> proc_macro2::TokenStream { - let syn::Fields::Named(FieldsNamed { named, .. }) = fields else { - unimplemented!() - }; - let fields = named.into_iter().map(|field| { - let ident = field.ident.clone().unwrap(); - let ty = field.ty.clone(); - let message = format!("{}({})", ident, quote!(#ty)); - quote!(#ident: ::cw_orch_contract_cli::custom_type_serialize(#message)?) - }); - let derived_trait_impl = quote!( - #[automatically_derived] - impl ::cw_orch_contract_cli::ParseCwMsg for #name { - fn cw_parse(_state_interface: &impl ::cw_orch::environment::StateInterface) -> ::cw_orch_contract_cli::OrchCliResult { - Ok(Self { - #(#fields),* - }) - } - } - ); - derived_trait_impl -} diff --git a/packages/cw-orch-contract-cli/Cargo.toml b/packages/cw-orch-contract-cli/Cargo.toml deleted file mode 100644 index 89da82a49..000000000 --- a/packages/cw-orch-contract-cli/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "cw-orch-contract-cli" -version = "0.1.0" -authors.workspace = true -edition.workspace = true -license.workspace = true -repository.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -cw-orch-cli-derive = { path = "../cw-orch-cli-derive" } -thiserror = { workspace = true } -inquire = { version = "0.6" } -cw-orch = { path = "../../cw-orch", features = ["daemon"] } -cw-orch-cli = { path = "../../cw-orch-cli" } - -strum = { version = "0.24", features = ["derive"] } -cosmwasm-std = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } diff --git a/packages/cw-orch-contract-cli/src/contract/error.rs b/packages/cw-orch-contract-cli/src/contract/error.rs deleted file mode 100644 index 829c0a753..000000000 --- a/packages/cw-orch-contract-cli/src/contract/error.rs +++ /dev/null @@ -1,15 +0,0 @@ -use cw_orch::prelude::CwOrchError; -use inquire::error::InquireError; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum OrchCliError { - #[error("{0}")] - InquireError(#[from] InquireError), - - #[error("{0}")] - CwOrchError(#[from] CwOrchError), - - #[error("Custom Error val: {val:?}")] - CustomError { val: String }, -} diff --git a/packages/cw-orch-contract-cli/src/contract/mod.rs b/packages/cw-orch-contract-cli/src/contract/mod.rs deleted file mode 100644 index ffe1cc168..000000000 --- a/packages/cw-orch-contract-cli/src/contract/mod.rs +++ /dev/null @@ -1,236 +0,0 @@ -mod error; - -use std::{ - fmt::{Display, Write}, - sync::Arc, -}; - -pub type OrchCliResult = Result; - -use cosmwasm_std::{Addr, Coin, Empty}; -use cw_orch::{ - daemon::DaemonState, - environment::ChainState, - prelude::{ - ContractInstance, CwOrchExecute, CwOrchInstantiate, CwOrchMigrate, CwOrchQuery, - CwOrchUpload, Daemon, ExecutableContract, InstantiableContract, MigratableContract, - QueryableContract, - }, -}; - -use inquire::{error::InquireResult, ui::RenderConfig, Confirm, CustomType, InquireError, Text}; -use serde::{de::DeserializeOwned, Serialize}; -use strum::{Display, EnumIter, IntoEnumIterator}; - -pub use self::error::OrchCliError; - -#[derive(EnumIter, Display)] -enum ActionVariants { - Execute, - Query, - Upload, - Instantiate, - Migrate, - ContractInfo, - Addons, - Quit, -} - -#[derive(Serialize)] -#[allow(dead_code)] -struct ContractInfo { - addr: Option, - code_id: Option, -} - -pub trait ContractCli -where - C: AddonsContext, - Self: ContractInstance - + CwOrchUpload - + InstantiableContract - + ExecutableContract - + QueryableContract - + MigratableContract - + CwCliAddons, - ::InstantiateMsg: ParseCwMsg, - ::ExecuteMsg: ParseCwMsg, - ::QueryMsg: ParseCwMsg, - ::MigrateMsg: ParseCwMsg, -{ - fn select_action(mut self, context: C) -> OrchCliResult<()> { - let state_interface = self.get_chain().state(); - loop { - let action = - inquire::Select::new("Select action", ActionVariants::iter().collect()).prompt()?; - let res = match action { - ActionVariants::Execute => self.execute_cli(&state_interface), - ActionVariants::Query => self.query_cli(&state_interface), - ActionVariants::Upload => { - self.upload()?; - println!("Code_id: {}", self.code_id().unwrap()); - Ok(()) - } - ActionVariants::Instantiate => self.instantiate_cli(&state_interface), - ActionVariants::Migrate => self.migrate_cli(&state_interface), - ActionVariants::ContractInfo => { - let contract_info = ContractInfo { - addr: self.address().ok(), - code_id: self.code_id().ok(), - }; - println!("{}", serde_json::to_string_pretty(&contract_info).unwrap()); - Ok(()) - } - ActionVariants::Addons => self.addons(context.clone()), - ActionVariants::Quit => return Ok(()), - }; - match res { - Err(OrchCliError::InquireError(InquireError::OperationCanceled)) | Ok(_) => {} - Err(err) => { - // Unrecoverable error? - return Err(err); - } - } - } - } - - fn instantiate_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { - let instantiate_msg = - ::InstantiateMsg::cw_parse(state_interface)?; - let coins = cw_orch_cli::common::parse_coins()?; - - let admin = Text::new("Admin addr") - .with_help_message("Press ESC to not set admin") - .prompt_skippable()? - .map(Addr::unchecked); - - if helpers::confirm_action("Execute", &instantiate_msg, Some(&coins.to_vec()))? { - let res = self.instantiate(&instantiate_msg, admin.as_ref(), Some(&coins.to_vec()))?; - println!( - "Instantiation succesfull\naddr: {}\nhash: {}", - self.addr_str()?, - res.txhash - ); - } - Ok(()) - } - - fn execute_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { - let execute_msg = ::ExecuteMsg::cw_parse(state_interface)?; - // TODO: figure out a way to make this only with `payable` attribute - let coins = cw_orch_cli::common::parse_coins()?; - - if helpers::confirm_action("Execute", &execute_msg, Some(&coins.to_vec()))? { - let res = self.execute(&execute_msg, Some(&coins.to_vec()))?; - println!("Execution succesfull, hash: {}", res.txhash); - } - Ok(()) - } - - fn query_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { - let query_msg = ::QueryMsg::cw_parse(state_interface)?; - - let resp: serde_json::Value = self.query(&query_msg)?; - println!("{}", serde_json::to_string_pretty(&resp).unwrap()); - Ok(()) - } - - fn migrate_cli(&self, state_interface: &Arc) -> OrchCliResult<()> { - let new_code_id = inquire::CustomType::::new("New code_id").prompt()?; - let migrate_msg = ::MigrateMsg::cw_parse(state_interface)?; - - if helpers::confirm_action("Migrate", &migrate_msg, None)? { - let res = self.migrate(&migrate_msg, new_code_id)?; - println!("Migrate succesfull, hash: {}", res.txhash); - } - Ok(()) - } -} - -pub trait ParseCwMsg -where - Self: Sized, -{ - fn cw_parse(state: &impl cw_orch::environment::StateInterface) -> OrchCliResult; -} - -impl ParseCwMsg for Empty { - fn cw_parse(_state: &impl cw_orch::environment::StateInterface) -> OrchCliResult { - Ok(Empty {}) - } -} - -pub trait AddonsContext: Clone {} - -impl AddonsContext for T {} - -pub trait CwCliAddons { - fn addons(&mut self, context: AddonsContext) -> OrchCliResult<()> - where - Self: ContractInstance; -} - -impl ContractCli for T -where - C: AddonsContext, - T: ContractInstance - + CwOrchUpload - + InstantiableContract - + ExecutableContract - + QueryableContract - + MigratableContract - + CwCliAddons, - ::InstantiateMsg: ParseCwMsg, - ::ExecuteMsg: ParseCwMsg, - ::QueryMsg: ParseCwMsg, - ::MigrateMsg: ParseCwMsg, -{ -} - -pub mod helpers { - use super::*; - - pub fn custom_type_serialize( - message: &str, - ) -> InquireResult { - let msg = CustomType { - message, - default: None, - placeholder: None, - help_message: None, - formatter: &|val: Msg| serde_json::to_string(&val).unwrap(), - default_value_formatter: &|val| serde_json::to_string(&val).unwrap(), - parser: &|input| serde_json::from_str(input).map_err(|_| ()), - validators: CustomType::DEFAULT_VALIDATORS, - error_message: "Serialization failed".to_owned(), - render_config: RenderConfig::default_colored(), - } - .prompt()?; - - Ok(msg) - } - - pub fn select_msg(options: Vec) -> InquireResult { - let variant = inquire::Select::new("Select Message", options).prompt()?; - Ok(variant) - } - - pub fn confirm_action( - action: &str, - message: T, - coins: Option<&[Coin]>, - ) -> InquireResult { - let mut message = format!( - "Confirm {action}, with message: {}", - serde_json::to_string(&message).unwrap() - ); - if let Some(c) = coins { - let coins_str = c.iter().map(|c| c.to_string()).collect::>(); - write!(message, ", and attached coins: {coins_str:?} y/n?",).unwrap(); - } - Ok(Confirm::new(&message) - .with_default(true) - .prompt_skippable()? - == Some(true)) - } -} diff --git a/packages/cw-orch-contract-cli/src/daemon/mod.rs b/packages/cw-orch-contract-cli/src/daemon/mod.rs deleted file mode 100644 index 326be49a3..000000000 --- a/packages/cw-orch-contract-cli/src/daemon/mod.rs +++ /dev/null @@ -1,21 +0,0 @@ -use cw_orch::{ - anyhow::anyhow, - prelude::{networks::parse_network, Daemon, DaemonBuilder}, - tokio::runtime::Handle, -}; - -pub trait DaemonFromCli { - fn from_cli(handle: &Handle) -> cw_orch::anyhow::Result { - let network_str = inquire::Text::new("Chain id") - .with_placeholder("uni-6") - .prompt()?; - let network = parse_network(&network_str).map_err(|e| anyhow!(e))?; - let chain = DaemonBuilder::default() - .handle(handle) - .chain(network) - .build()?; - Ok(chain) - } -} - -impl DaemonFromCli for Daemon {} diff --git a/packages/cw-orch-contract-cli/src/lib.rs b/packages/cw-orch-contract-cli/src/lib.rs deleted file mode 100644 index 8c589c917..000000000 --- a/packages/cw-orch-contract-cli/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -/// Allow integrating keys and stuff -mod contract; -mod daemon; - -pub use daemon::DaemonFromCli; - -pub use cw_orch_cli_derive::ParseCwMsg; - -pub use contract::{ - // Helpers used by derive macro - helpers::{custom_type_serialize, select_msg}, - AddonsContext, - ContractCli, - CwCliAddons, - OrchCliError, - OrchCliResult, - ParseCwMsg, -}; From 17a7a2f9dbc3a9951239fc5b5137f9ebcb67915d Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 16:21:47 +0200 Subject: [PATCH 107/135] fix readme --- cw-orch-cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index dd086e20e..313a32d00 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -66,4 +66,4 @@ cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms - -m, --merge-cw-orch-state - merge cw-orch state file(`STATE_FILE` [cw-orch env variable]) with address-book (address book have higher priority) - --deployment-id - cw-orch state deployment-id, defaults to "default" -[cw-orch env variable]: ../docs/src/contracts/env-variable.md \ No newline at end of file +[cw-orch env variable]: ../docs/src/contracts/env-variable.md From 1dd817bd7e58cc30d1420fe6752c8f5fe904a9b6 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 17:10:48 +0200 Subject: [PATCH 108/135] include cw-orch-cli as workspace member --- Cargo.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 588f7d50d..0bd8aec84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,11 @@ [workspace] -members = ["cw-orch", "cw-orch-daemon", "packages/*", "contracts/*"] +members = [ + "cw-orch", + "cw-orch-cli", + "cw-orch-daemon", + "packages/*", + "contracts/*", +] resolver = "2" [workspace.package] From 4ac2ff5dd032cf2ffe80e74ed45f3c8798467c0e Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 17:14:38 +0200 Subject: [PATCH 109/135] force disable cw-orch state merging for address_book::remove_address --- cw-orch-cli/src/commands/address_book/remove_address.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cw-orch-cli/src/commands/address_book/remove_address.rs b/cw-orch-cli/src/commands/address_book/remove_address.rs index c1a8f39b7..4b9eacf70 100644 --- a/cw-orch-cli/src/commands/address_book/remove_address.rs +++ b/cw-orch-cli/src/commands/address_book/remove_address.rs @@ -13,7 +13,11 @@ pub struct RemoveAddress { impl RemoveAddress { pub fn input_alias(context: &AddresBookContext) -> color_eyre::eyre::Result> { - address_book::select_alias(context.chain.chain_info(), &context.global_config) + // Disable state merging, CLI do not remove items from cw-orch state + let mut config = context.global_config.clone(); + config.merge_cw_orch_state = false; + + address_book::select_alias(context.chain.chain_info(), &config) } } From ada5eccc6b8987a455cac6e27b543f7e2f44cf53 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 17:17:05 +0200 Subject: [PATCH 110/135] Remove msg postfix for a file message type --- .../src/commands/action/cosmwasm/msg_type/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index e912f57b9..7a5b87011 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -16,8 +16,8 @@ pub enum MsgType { /// Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==) Base64Msg, /// Read from a file (e.g. file.json) - #[strum_discriminants(strum(message = "File message"))] - FileMsg, + #[strum_discriminants(strum(message = "Read from a file"))] + File, } impl interactive_clap::ToCli for MsgType { @@ -30,7 +30,7 @@ impl std::str::FromStr for MsgType { match s { "json-msg" => Ok(Self::JsonMsg), "base64-msg" => Ok(Self::Base64Msg), - "file-msg" => Ok(Self::FileMsg), + "file" => Ok(Self::File), _ => Err("MsgType: incorrect message type".to_string()), } } @@ -41,7 +41,7 @@ impl std::fmt::Display for MsgType { match self { Self::JsonMsg => write!(f, "json-msg"), Self::Base64Msg => write!(f, "base64-msg"), - Self::FileMsg => write!(f, "file-msg"), + Self::File => write!(f, "file"), } } } @@ -51,7 +51,7 @@ impl std::fmt::Display for MsgTypeDiscriminants { match self { Self::JsonMsg => write!(f, "Json Msg"), Self::Base64Msg => write!(f, "Base64 Msg"), - Self::FileMsg => write!(f, "File Msg"), + Self::File => write!(f, "File"), } } } @@ -62,7 +62,7 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { match selected { MsgTypeDiscriminants::JsonMsg => Ok(Some(MsgType::JsonMsg)), MsgTypeDiscriminants::Base64Msg => Ok(Some(MsgType::Base64Msg)), - MsgTypeDiscriminants::FileMsg => Ok(Some(MsgType::FileMsg)), + MsgTypeDiscriminants::File => Ok(Some(MsgType::File)), } } @@ -113,7 +113,7 @@ pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre .decode(message) .wrap_err("Failed to decode base64 string") } - MsgType::FileMsg => { + MsgType::File => { let file_path = std::path::PathBuf::from(message_or_file); let msg_bytes = std::fs::read(file_path.as_path()).wrap_err("Failed to read a message file")?; From bc7971ecd473b213dfe44df3f517be6ba62431ce Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 17:42:37 +0200 Subject: [PATCH 111/135] clippy --- contracts/counter/tests/checksum.rs | 2 +- cw-orch-cli/src/types/keys.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/counter/tests/checksum.rs b/contracts/counter/tests/checksum.rs index 448596920..c12602708 100644 --- a/contracts/counter/tests/checksum.rs +++ b/contracts/counter/tests/checksum.rs @@ -12,7 +12,7 @@ fn checksum() { let lines = io::BufReader::new(file).lines(); let mut found = false; - for line in lines.flatten() { + for line in lines.map_while(Result::ok) { if line.contains("counter_contract.wasm") { let parts: Vec<&str> = line.split_whitespace().collect(); if parts.len() > 1 { diff --git a/cw-orch-cli/src/types/keys.rs b/cw-orch-cli/src/types/keys.rs index 98704304b..c40d23847 100644 --- a/cw-orch-cli/src/types/keys.rs +++ b/cw-orch-cli/src/types/keys.rs @@ -41,6 +41,7 @@ pub fn save_entry_if_required(entry: &str) -> color_eyre::Result<()> { .read(true) .write(true) .create(true) + .truncate(false) .open(entries_list_file.as_path())?; let mut entries_set: EntriesSet = if file.metadata()?.len().eq(&0) { Default::default() @@ -67,6 +68,7 @@ pub fn remove_entry(entry: &str) -> color_eyre::Result<()> { .read(true) .write(true) .create(true) + .truncate(false) .open(entries_list_file.as_path())?; let mut entries_set: EntriesSet = if file.metadata()?.len().eq(&0) { Default::default() From 9bd5df7ea9b23216af0d90f5c47396c701f9d00f Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 17:47:29 +0200 Subject: [PATCH 112/135] bump msrv --- .github/workflows/check.yml | 2 +- CHANGELOG.md | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 13c3f0f82..ee6b6b6a6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -79,7 +79,7 @@ jobs: # https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability strategy: matrix: - msrv: [1.72.0] # dep/feat syntax fixed with co-exist dep + msrv: [1.74.0] # clap-derive of cw-orch-cli requires 1.74 or newer name: ubuntu / ${{ matrix.msrv }} steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 621169700..dddcde33d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # cw-orchestrator Changelog +## Unreleased + +- Bumped MSRV to 1.74 because of dependency `clap_derive@4.5.3` + ## 0.21.0 - Updated cw-multi-test to allow for IBC packet timeout From c83ecae74cfba9a0961417c17a1506f87b672103 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 18:46:38 +0200 Subject: [PATCH 113/135] merge-cw-orch-state > source-state-file --- cw-orch-cli/README.md | 2 +- .../src/commands/address_book/remove_address.rs | 2 +- cw-orch-cli/src/lib.rs | 10 +++++----- cw-orch-cli/src/types/address_book.rs | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index 313a32d00..1b93b804a 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -63,7 +63,7 @@ cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms ### Global optional arguments - `-v` or `--verbose` - enable verbose mode, this will log actions from cw-orch daemon executions that corresponds to your `RUST_LOG` level -- -m, --merge-cw-orch-state - merge cw-orch state file(`STATE_FILE` [cw-orch env variable]) with address-book (address book have higher priority) +- `-s` or `--source-state-file` - source cw-orch state file(`STATE_FILE` [cw-orch env variable]) to use together with address-book entries (address book have higher priority) - --deployment-id - cw-orch state deployment-id, defaults to "default" [cw-orch env variable]: ../docs/src/contracts/env-variable.md diff --git a/cw-orch-cli/src/commands/address_book/remove_address.rs b/cw-orch-cli/src/commands/address_book/remove_address.rs index 4b9eacf70..eb59dc686 100644 --- a/cw-orch-cli/src/commands/address_book/remove_address.rs +++ b/cw-orch-cli/src/commands/address_book/remove_address.rs @@ -15,7 +15,7 @@ impl RemoveAddress { pub fn input_alias(context: &AddresBookContext) -> color_eyre::eyre::Result> { // Disable state merging, CLI do not remove items from cw-orch state let mut config = context.global_config.clone(); - config.merge_cw_orch_state = false; + config.source_state_file = false; address_book::select_alias(context.chain.chain_info(), &config) } diff --git a/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs index d773cff85..231dd5521 100644 --- a/cw-orch-cli/src/lib.rs +++ b/cw-orch-cli/src/lib.rs @@ -12,11 +12,11 @@ pub struct TLCommand { /// Verbose mode #[interactive_clap(short, long, global = true)] verbose: bool, - /// Merge cw-orch state file in address-book + /// Source cw-orch state file with address-book #[interactive_clap(short, long, global = true)] - merge_cw_orch_state: bool, + source_state_file: bool, /// Deployment id, that will be used for merging cw_orch_state - #[interactive_clap(long = "deployment-id", global = true)] + #[interactive_clap(long, global = true)] #[interactive_clap(skip_interactive_input)] deployment_id: Option, #[interactive_clap(subcommand)] @@ -25,7 +25,7 @@ pub struct TLCommand { #[derive(Debug, Clone)] pub struct GlobalConfig { - merge_cw_orch_state: bool, + source_state_file: bool, deployment_id: String, } @@ -38,7 +38,7 @@ impl GlobalConfig { pretty_env_logger::init() } Ok(Self { - merge_cw_orch_state: scope.merge_cw_orch_state, + source_state_file: scope.source_state_file, deployment_id: scope .deployment_id .clone() diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index b6b276a9f..2b00d9717 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -64,8 +64,8 @@ pub fn get_account_id( name_alias: &str, ) -> color_eyre::Result> { let account_id_address_book = get_account_id_address_book(chain, name_alias)?; - // If address found in address book or cw-orch state merge disabled - no need to read cw orch state - if account_id_address_book.is_some() || !global_config.merge_cw_orch_state { + // If address found in address book or cw-orch state sourcing disabled - no need to read cw orch state + if account_id_address_book.is_some() || !global_config.source_state_file { return Ok(account_id_address_book); } // Try to load cw orch state contract @@ -210,7 +210,7 @@ pub fn get_or_prompt_account_id( }; } // Try to retrieve from cw-orch state if merging enabled - if global_config.merge_cw_orch_state { + if global_config.source_state_file { let cw_orch_contracts = cw_orch_state_contracts(chain, &global_config.deployment_id)?; if let Some(contract) = cw_orch_contracts.get(name_alias) { let contract_addr = contract @@ -249,7 +249,7 @@ pub fn select_alias( ) -> color_eyre::eyre::Result> { let chain_id = chain_info.chain_id; - let cw_orch_contracts = if global_config.merge_cw_orch_state { + let cw_orch_contracts = if global_config.source_state_file { cw_orch_state_contracts(chain_info, &global_config.deployment_id)? } else { Default::default() From 17dc4ea1e3350cb242c60eea81d09657a9dc8d62 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 15 Mar 2024 18:53:36 +0200 Subject: [PATCH 114/135] newline on errors --- cw-orch-cli/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs index 046f1a180..f33f667eb 100644 --- a/cw-orch-cli/src/main.rs +++ b/cw-orch-cli/src/main.rs @@ -35,7 +35,7 @@ fn main() -> color_eyre::Result<()> { interactive_clap::ResultFromCli::Err(cli_args, err) => { if let Some(cli_args) = cli_args { println!( - "Your console command: {}", + "\nYour console command: {}", shell_words::join(std::iter::once(cw_cli_path).chain(cli_args.to_cli_args())) ); } From f1f05f31937b7a8b15653876b0401dbcabe41c21 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Apr 2024 17:18:16 +0300 Subject: [PATCH 115/135] Log url of tx --- cw-orch-cli/Cargo.toml | 1 + .../commands/action/asset/send_cw20/mod.rs | 4 +- .../commands/action/asset/send_native/mod.rs | 4 +- .../commands/action/cosmwasm/execute/mod.rs | 4 +- .../action/cosmwasm/instantiate/mod.rs | 3 +- .../commands/action/cosmwasm/msg_type/mod.rs | 40 ++++++++----------- .../commands/action/cosmwasm/query/raw/mod.rs | 1 + .../action/cosmwasm/query/smart/mod.rs | 1 + .../src/commands/action/cosmwasm/store/mod.rs | 3 +- .../commands/action/cw_ownable/accept/mod.rs | 14 ++++--- .../src/commands/action/cw_ownable/get/mod.rs | 1 + .../action/cw_ownable/renounce/mod.rs | 14 ++++--- .../action/cw_ownable/transfer/mod.rs | 10 +++-- cw-orch-cli/src/commands/keys/add_key/mod.rs | 3 +- cw-orch-cli/src/fetch/explorers.rs | 22 ++++++++++ cw-orch-cli/src/fetch/mod.rs | 1 + cw-orch-cli/src/lib.rs | 1 + cw-orch-cli/src/log/mod.rs | 31 ++++++++++++-- 18 files changed, 110 insertions(+), 48 deletions(-) create mode 100644 cw-orch-cli/src/fetch/explorers.rs create mode 100644 cw-orch-cli/src/fetch/mod.rs diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 1987512c9..9e38210d2 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -14,6 +14,7 @@ cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.21" } # Logs pretty_env_logger = { version = "0.5.0" } +async-trait = { version = "0.1" } # Cosmos cosmwasm-std = { workspace = true } diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index 95b4e9c4a..19a2ec897 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -69,12 +69,12 @@ impl SendCw20Output { msg, funds: vec![], }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; - resp.log(); + resp.log(chain.chain_info()); Ok(SendCw20Output) } diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index a6fbe99e3..76ac824dd 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -66,12 +66,12 @@ impl SendNativeOutput { to_address, amount: coins, }; - let resp = daemon.sender.commit_tx(vec![transfer_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![transfer_msg], None).await?; color_eyre::Result::::Ok(resp) })?; - resp.log(); + resp.log(chain.chain_info()); Ok(SendNativeOutput) } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 64df91f7f..aafe64be6 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -81,12 +81,12 @@ impl ExecuteWasmOutput { msg, funds: coins, }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; - resp.log(); + resp.log(chain.chain_info()); Ok(ExecuteWasmOutput) } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 06864f193..65a5f47e2 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -87,12 +87,13 @@ impl InstantiateWasmOutput { msg, funds: coins, }; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; + resp.log(chain.chain_info()); let address = resp.instantiated_contract_address()?; - resp.log(); println!("Address of the instantiated contract: {address}"); // Maybe save it in Address Book diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index 7a5b87011..d795c9100 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -15,9 +15,12 @@ pub enum MsgType { #[strum_discriminants(strum(message = "base64 message"))] /// Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==) Base64Msg, - /// Read from a file (e.g. file.json) #[strum_discriminants(strum(message = "Read from a file"))] + /// Read from a file (e.g. file.json) File, + #[strum_discriminants(strum(message = "Use your editor"))] + /// Open editor (uses EDITOR env variable) to input message + Editor, } impl interactive_clap::ToCli for MsgType { @@ -31,6 +34,7 @@ impl std::str::FromStr for MsgType { "json-msg" => Ok(Self::JsonMsg), "base64-msg" => Ok(Self::Base64Msg), "file" => Ok(Self::File), + "editor" => Ok(Self::Editor), _ => Err("MsgType: incorrect message type".to_string()), } } @@ -42,6 +46,7 @@ impl std::fmt::Display for MsgType { Self::JsonMsg => write!(f, "json-msg"), Self::Base64Msg => write!(f, "base64-msg"), Self::File => write!(f, "file"), + Self::Editor => write!(f, "editor"), } } } @@ -52,6 +57,7 @@ impl std::fmt::Display for MsgTypeDiscriminants { Self::JsonMsg => write!(f, "Json Msg"), Self::Base64Msg => write!(f, "Base64 Msg"), Self::File => write!(f, "File"), + Self::Editor => write!(f, "Editor"), } } } @@ -63,6 +69,7 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { MsgTypeDiscriminants::JsonMsg => Ok(Some(MsgType::JsonMsg)), MsgTypeDiscriminants::Base64Msg => Ok(Some(MsgType::Base64Msg)), MsgTypeDiscriminants::File => Ok(Some(MsgType::File)), + MsgTypeDiscriminants::Editor => Ok(Some(MsgType::File)), } } @@ -76,28 +83,8 @@ pub fn input_msg_or_filename() -> color_eyre::eyre::Result> { pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { - let message = match message_or_file.is_empty() { - false => message_or_file, - // If message empty - give editor input - true => inquire::Editor::new("Enter message") - .with_help_message(r#"Valid JSON string (e.g. {"foo": "bar"})"#) - .with_predefined_text("{}") - .with_file_extension(".json") - .with_validator(|s: &str| match serde_json::Value::from_str(s) { - Ok(_) => Ok(inquire::validator::Validation::Valid), - Err(_) => Ok(inquire::validator::Validation::Invalid( - inquire::validator::ErrorMessage::Custom( - "Message not in JSON format!".to_owned(), - ), - )), - }) - .with_formatter(&|s| { - serde_json::to_string(&serde_json::Value::from_str(s).unwrap()).unwrap() - }) - .prompt()?, - }; - let message_json = - serde_json::Value::from_str(&message).wrap_err("Message not in JSON format")?; + let message_json = serde_json::Value::from_str(&message_or_file) + .wrap_err("Message not in JSON format")?; serde_json::to_vec(&message_json).wrap_err("Unexpected error") } @@ -119,6 +106,13 @@ pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre std::fs::read(file_path.as_path()).wrap_err("Failed to read a message file")?; Ok(msg_bytes) } + MsgType::Editor => { + let message = inquire::Editor::new("Enter message") + .with_predefined_text("{}") + .with_file_extension(".json") + .prompt()?; + Ok(message.into_bytes()) + } } } diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index c1ba281e1..0541595b4 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -35,6 +35,7 @@ impl QueryWasmOutput { let chain_data: ChainRegistryData = chain.into(); let rt = Runtime::new()?; + // TODO: replace by no-signer daemon let resp = rt.block_on(async { let grpc_channel = GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index 52c20e14e..ef41a72cd 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -54,6 +54,7 @@ impl QueryWasmOutput { let chain_data: ChainRegistryData = chain.into(); let rt = Runtime::new()?; + // TODO: replace by no-signer daemon let resp = rt.block_on(async { let grpc_channel = GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index 7ba1e8dd6..c88f051ce 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -51,12 +51,13 @@ impl StoreWasmOutput { wasm_byte_code, instantiate_permission: None, }; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; + resp.log(chain.chain_info()); let code_id = resp.uploaded_code_id().unwrap(); - resp.log(); println!("code_id: {code_id}"); Ok(StoreWasmOutput) diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 09ae20271..9da855c6f 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,7 +1,11 @@ -use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; +use cw_orch::{ + daemon::{CosmTxResponse, DaemonAsync}, + tokio::runtime::Runtime, +}; use crate::{ commands::action::CosmosContext, + log::LogOutput, types::{keys::seed_phrase_for_id, CliAddress}, }; @@ -41,7 +45,7 @@ impl AcceptOwnershipOutput { let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) @@ -55,10 +59,10 @@ impl AcceptOwnershipOutput { funds: vec![], }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; - - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + color_eyre::Result::::Ok(resp) })?; + resp.log(chain.chain_info()); Ok(AcceptOwnershipOutput) } diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index 195044cb4..f1a8d1ef9 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -35,6 +35,7 @@ impl GetOwnershipOutput { let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; let chain_data: ChainRegistryData = chain.into(); + // TODO: replace by no-signer daemon let rt = Runtime::new()?; rt.block_on(async { let grpc_channel = diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index 0d46b54b8..0e78fe738 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -1,7 +1,11 @@ -use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; +use cw_orch::{ + daemon::{CosmTxResponse, DaemonAsync}, + tokio::runtime::Runtime, +}; use crate::{ commands::action::CosmosContext, + log::LogOutput, types::{keys::seed_phrase_for_id, CliAddress}, }; @@ -41,7 +45,7 @@ impl RenounceOwnershipOutput { let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; let rt = Runtime::new()?; - rt.block_on(async { + let resp = rt.block_on(async { let daemon = DaemonAsync::builder() .chain(chain) .mnemonic(sender_seed) @@ -55,10 +59,10 @@ impl RenounceOwnershipOutput { funds: vec![], }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; - - color_eyre::Result::<(), color_eyre::Report>::Ok(()) + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + color_eyre::Result::::Ok(resp) })?; + resp.log(chain.chain_info()); Ok(RenounceOwnershipOutput) } diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index e47831c84..7f65917f6 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -6,6 +6,7 @@ use cw_orch::{ use crate::{ commands::action::CosmosContext, common::parse_expiration, + log::LogOutput, types::{keys::seed_phrase_for_id, CliAddress, CliExpiration, CliSkippable}, }; @@ -84,9 +85,10 @@ impl TransferOwnershipOutput { funds: vec![], }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; - // TODO: logging + resp.log(chain.chain_info()); + println!("Successfully transferred ownership, waiting for approval by {new_owner}",); if let Some(seed) = receiver_seed { let receiver_sender = @@ -100,7 +102,9 @@ impl TransferOwnershipOutput { msg, funds: vec![], }; - let _res = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + resp.log(chain.chain_info()); + println!("{new_owner} successfully accepted ownership"); } color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; diff --git a/cw-orch-cli/src/commands/keys/add_key/mod.rs b/cw-orch-cli/src/commands/keys/add_key/mod.rs index 7825a6935..1a11aba91 100644 --- a/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -3,7 +3,7 @@ use cosmrs::bip32; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; use crate::common::B64; -use crate::types::keys::entry_for_seed; +use crate::types::keys::{entry_for_seed, save_entry_if_required}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] @@ -67,6 +67,7 @@ impl AddKeyOutput { let entry = entry_for_seed(&name)?; let password = B64.encode(mnemonic.phrase().as_bytes()); entry.set_password(&password)?; + save_entry_if_required(&name)?; Ok(AddKeyOutput) } } diff --git a/cw-orch-cli/src/fetch/explorers.rs b/cw-orch-cli/src/fetch/explorers.rs new file mode 100644 index 000000000..d4042765a --- /dev/null +++ b/cw-orch-cli/src/fetch/explorers.rs @@ -0,0 +1,22 @@ +use cw_orch::daemon::Fetchable; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(default)] +pub struct Explorers(pub Vec); + +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[serde(default)] +pub struct Explorer { + pub kind: String, + pub url: String, + pub tx_page: Option, + pub account_page: Option, +} + +impl Fetchable for Explorers { + fn path(resource: &str) -> PathBuf { + [resource, "chain.json"].iter().collect() + } +} diff --git a/cw-orch-cli/src/fetch/mod.rs b/cw-orch-cli/src/fetch/mod.rs new file mode 100644 index 000000000..264cebff3 --- /dev/null +++ b/cw-orch-cli/src/fetch/mod.rs @@ -0,0 +1 @@ +pub(crate) mod explorers; diff --git a/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs index 231dd5521..94eeb2e07 100644 --- a/cw-orch-cli/src/lib.rs +++ b/cw-orch-cli/src/lib.rs @@ -1,5 +1,6 @@ pub mod commands; pub mod common; +pub(crate) mod fetch; pub(crate) mod log; pub(crate) mod types; diff --git a/cw-orch-cli/src/log/mod.rs b/cw-orch-cli/src/log/mod.rs index 78dd373a1..36916916d 100644 --- a/cw-orch-cli/src/log/mod.rs +++ b/cw-orch-cli/src/log/mod.rs @@ -1,11 +1,36 @@ -use cw_orch::daemon::CosmTxResponse; +use cw_orch::{ + daemon::{ChainInfo, ChainKind, CosmTxResponse, Fetchable}, + tokio::runtime::Runtime, +}; + +use crate::fetch::explorers::Explorers; pub trait LogOutput { - fn log(&self); + fn log(&self, chain_info: &ChainInfo); } impl LogOutput for CosmTxResponse { - fn log(&self) { + fn log(&self, chain_info: &ChainInfo) { println!("Transaction hash: {}", self.txhash); + // TODO: should be allowed for any type of chain ORC-119 + if let ChainKind::Mainnet = chain_info.kind { + let log_explorer_url = || -> cw_orch::anyhow::Result<()> { + let rt = Runtime::new()?; + let Explorers(explorers) = rt.block_on(Explorers::fetch( + chain_info.network_info.id.to_owned(), + None, + ))?; + for explorer in explorers { + if let Some(tx_page) = explorer.tx_page { + let url = tx_page.replace("${txHash}", &self.txhash); + println!("{url}"); + break; + } + } + Ok(()) + }; + // Ignore any errors + let _ = log_explorer_url(); + } } } From 8d5cc63c4f23109f170d9f1aa551ccf07baea30c Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Apr 2024 18:26:24 +0300 Subject: [PATCH 116/135] add explorer to any address --- .github/codecov.yml | 1 + .../src/commands/address_book/show_address.rs | 16 ++++++++-- cw-orch-cli/src/commands/keys/add_key/mod.rs | 29 +++++++++++++++++-- .../src/commands/keys/remove_key/mod.rs | 1 + .../src/commands/keys/show_address/mod.rs | 10 ++++++- cw-orch-cli/src/commands/mod.rs | 4 +-- cw-orch-cli/src/common.rs | 16 ++++++++-- cw-orch-cli/src/fetch/explorers.rs | 4 ++- cw-orch-cli/src/fetch/mod.rs | 2 +- cw-orch-cli/src/lib.rs | 2 +- cw-orch-cli/src/log/mod.rs | 4 +-- cw-orch-cli/src/main.rs | 2 +- cw-orch-cli/src/types/keys.rs | 8 +++-- 13 files changed, 82 insertions(+), 17 deletions(-) diff --git a/.github/codecov.yml b/.github/codecov.yml index c7e0de38d..cbd4fefb4 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -16,6 +16,7 @@ ignore: - "tests" - "**/examples" - "**/schema.rs" + - "cw-orch-cli" # Make comments less noisy comment: diff --git a/cw-orch-cli/src/commands/address_book/show_address.rs b/cw-orch-cli/src/commands/address_book/show_address.rs index 2ddff4ead..f75fe84b2 100644 --- a/cw-orch-cli/src/commands/address_book/show_address.rs +++ b/cw-orch-cli/src/commands/address_book/show_address.rs @@ -1,4 +1,9 @@ -use crate::types::address_book::{self, select_alias}; +use cw_orch::tokio::runtime::Runtime; + +use crate::{ + common::show_addr_explorer, + types::address_book::{self, select_alias}, +}; use super::AddresBookContext; @@ -32,7 +37,14 @@ impl ShowAddressOutput { )?; match maybe_account_id { - Some(account_id) => println!("{account_id}"), + Some(account_id) => { + println!("{account_id}"); + let runtime = Runtime::new()?; + let _ = runtime.block_on(show_addr_explorer( + chain.chain_info().network_info.id.to_owned(), + &account_id.to_string(), + )); + } None => println!("Address not found"), } diff --git a/cw-orch-cli/src/commands/keys/add_key/mod.rs b/cw-orch-cli/src/commands/keys/add_key/mod.rs index 1a11aba91..8b1be29e1 100644 --- a/cw-orch-cli/src/commands/keys/add_key/mod.rs +++ b/cw-orch-cli/src/commands/keys/add_key/mod.rs @@ -3,19 +3,43 @@ use cosmrs::bip32; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; use crate::common::B64; -use crate::types::keys::{entry_for_seed, save_entry_if_required}; +use crate::types::keys::{entry_for_seed, read_entries, save_entry_if_required}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] #[interactive_clap(output_context = AddKeyContext)] pub struct AddKeyCommand { - // TODO: add checker for repetition + #[interactive_clap(skip_default_input_arg)] /// Id of they key name: String, #[interactive_clap(subcommand)] key_actions: AddKeyActions, } +impl AddKeyCommand { + fn input_name(_context: &()) -> color_eyre::eyre::Result> { + let entries = read_entries()?; + let name = inquire::Text::new("Id of they key") + .with_validator(move |s: &str| { + if s.is_empty() { + return Ok(inquire::validator::Validation::Invalid( + inquire::validator::ErrorMessage::Custom( + "Empty key not allowed".to_owned(), + ), + )); + }; + if entries.entries.contains(s) { + return Ok(inquire::validator::Validation::Invalid( + inquire::validator::ErrorMessage::Custom("Key already exist".to_owned()), + )); + }; + Ok(inquire::validator::Validation::Valid) + }) + .prompt()?; + Ok(Some(name)) + } +} + #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[strum_discriminants(derive(EnumMessage, EnumIter))] #[interactive_clap(input_context = AddKeyContext)] @@ -68,6 +92,7 @@ impl AddKeyOutput { let password = B64.encode(mnemonic.phrase().as_bytes()); entry.set_password(&password)?; save_entry_if_required(&name)?; + println!("New key \"{name}\" added"); Ok(AddKeyOutput) } } diff --git a/cw-orch-cli/src/commands/keys/remove_key/mod.rs b/cw-orch-cli/src/commands/keys/remove_key/mod.rs index ded3e6c19..f4b38fe24 100644 --- a/cw-orch-cli/src/commands/keys/remove_key/mod.rs +++ b/cw-orch-cli/src/commands/keys/remove_key/mod.rs @@ -24,6 +24,7 @@ impl RemoveKeyOutput { let entry = entry_for_seed(&scope.name)?; entry.delete_password()?; crate::types::keys::remove_entry(&scope.name)?; + println!("Key \"{}\" got removed", scope.name); Ok(RemoveKeyOutput) } } diff --git a/cw-orch-cli/src/commands/keys/show_address/mod.rs b/cw-orch-cli/src/commands/keys/show_address/mod.rs index 782ad36ce..6933eba23 100644 --- a/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -1,6 +1,9 @@ use cw_orch::{daemon::DaemonAsync, tokio::runtime::Runtime}; -use crate::{types::keys::seed_phrase_for_id, types::CliLockedChain}; +use crate::{ + common::show_addr_explorer, + types::{keys::seed_phrase_for_id, CliLockedChain}, +}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = ())] @@ -41,6 +44,11 @@ impl ShowAddressOutput { .await?; let address = daemon.sender(); println!("Your address: {address}"); + let _ = show_addr_explorer( + chain.chain_info().network_info.id.to_owned(), + address.as_str(), + ) + .await; color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; Ok(ShowAddressOutput) diff --git a/cw-orch-cli/src/commands/mod.rs b/cw-orch-cli/src/commands/mod.rs index fd76bc863..b06d8beb4 100644 --- a/cw-orch-cli/src/commands/mod.rs +++ b/cw-orch-cli/src/commands/mod.rs @@ -18,10 +18,10 @@ pub enum Commands { #[strum_discriminants(strum(message = "🎬 Action"))] Action(action::CosmosCommands), /// Add, View or Remove key - #[strum_discriminants(strum(message = "🔑 Manage Keys"))] + #[strum_discriminants(strum(message = "🔑 Keys"))] Key(keys::KeyCommands), /// Handle Address Book - #[strum_discriminants(strum(message = "📖 Manage Address Book"))] + #[strum_discriminants(strum(message = "📖 Address Book"))] AddressBook(address_book::AddressBookCommands), // TODO: // 1) Config management diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index ff65a4491..960bd9be2 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -1,6 +1,6 @@ -use crate::types::CliLockedChain; +use crate::{fetch::explorers::Explorers, types::CliLockedChain}; pub use base64::prelude::BASE64_STANDARD as B64; -use cw_orch::daemon::networks::SUPPORTED_NETWORKS as NETWORKS; +use cw_orch::daemon::{networks::SUPPORTED_NETWORKS as NETWORKS, Fetchable}; use inquire::{error::InquireResult, InquireError, Select}; pub fn get_cw_cli_exec_path() -> String { @@ -93,3 +93,15 @@ pub fn parse_expiration() -> InquireResult { }; Ok(expiration) } + +pub async fn show_addr_explorer(chain_name: String, addr: &str) -> color_eyre::eyre::Result<()> { + let Explorers { explorers } = Explorers::fetch(chain_name, None).await?; + for explorer in explorers { + if let Some(tx_page) = explorer.account_page { + let url = tx_page.replace("${accountAddress}", &addr); + println!("Explorer: {url}"); + break; + } + } + Ok(()) +} diff --git a/cw-orch-cli/src/fetch/explorers.rs b/cw-orch-cli/src/fetch/explorers.rs index d4042765a..d11f04fb7 100644 --- a/cw-orch-cli/src/fetch/explorers.rs +++ b/cw-orch-cli/src/fetch/explorers.rs @@ -4,7 +4,9 @@ use std::path::PathBuf; #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(default)] -pub struct Explorers(pub Vec); +pub struct Explorers { + pub explorers: Vec, +} #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(default)] diff --git a/cw-orch-cli/src/fetch/mod.rs b/cw-orch-cli/src/fetch/mod.rs index 264cebff3..d918f7f8f 100644 --- a/cw-orch-cli/src/fetch/mod.rs +++ b/cw-orch-cli/src/fetch/mod.rs @@ -1 +1 @@ -pub(crate) mod explorers; +pub mod explorers; diff --git a/cw-orch-cli/src/lib.rs b/cw-orch-cli/src/lib.rs index 94eeb2e07..e59997e7e 100644 --- a/cw-orch-cli/src/lib.rs +++ b/cw-orch-cli/src/lib.rs @@ -1,6 +1,6 @@ pub mod commands; pub mod common; -pub(crate) mod fetch; +pub mod fetch; pub(crate) mod log; pub(crate) mod types; diff --git a/cw-orch-cli/src/log/mod.rs b/cw-orch-cli/src/log/mod.rs index 36916916d..1ca8f3159 100644 --- a/cw-orch-cli/src/log/mod.rs +++ b/cw-orch-cli/src/log/mod.rs @@ -16,14 +16,14 @@ impl LogOutput for CosmTxResponse { if let ChainKind::Mainnet = chain_info.kind { let log_explorer_url = || -> cw_orch::anyhow::Result<()> { let rt = Runtime::new()?; - let Explorers(explorers) = rt.block_on(Explorers::fetch( + let Explorers { explorers } = rt.block_on(Explorers::fetch( chain_info.network_info.id.to_owned(), None, ))?; for explorer in explorers { if let Some(tx_page) = explorer.tx_page { let url = tx_page.replace("${txHash}", &self.txhash); - println!("{url}"); + println!("Explorer: {url}"); break; } } diff --git a/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs index f33f667eb..325eeddb2 100644 --- a/cw-orch-cli/src/main.rs +++ b/cw-orch-cli/src/main.rs @@ -5,7 +5,7 @@ use interactive_clap::{ResultFromCli, ToCliArgs}; fn main() -> color_eyre::Result<()> { // We don't want to see cw-orch logs during cli - std::env::set_var("CW_ORCH_DISABLE_ENABLE_LOGS_MESSAGE", "true"); + std::env::set_var("CW_ORCH_DISABLE_LOGS_ACTIVATION_MESSAGE", "true"); let render_config = RenderConfig { prompt: StyleSheet::new().with_attr(Attributes::BOLD), ..Default::default() diff --git a/cw-orch-cli/src/types/keys.rs b/cw-orch-cli/src/types/keys.rs index c40d23847..d21484137 100644 --- a/cw-orch-cli/src/types/keys.rs +++ b/cw-orch-cli/src/types/keys.rs @@ -27,9 +27,13 @@ fn entries_list_path() -> color_eyre::Result { pub fn read_entries() -> color_eyre::Result { let entries_list_file = entries_list_path()?; - let file = OpenOptions::new() + let maybe_file = OpenOptions::new() .read(true) - .open(entries_list_file.as_path())?; + .open(entries_list_file.as_path()); + // In case no file return empty + let Ok(file) = maybe_file else { + return Ok(Default::default()); + }; let entries_set: EntriesSet = serde_json::from_reader(file)?; Ok(entries_set) } From 5797c26a586e5e3ee7534894a77ab748108ff027 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Apr 2024 19:15:27 +0300 Subject: [PATCH 117/135] base64 raw queries --- .../commands/action/cosmwasm/execute/mod.rs | 7 +- .../action/cosmwasm/instantiate/mod.rs | 7 +- .../commands/action/cosmwasm/msg_type/mod.rs | 100 +++++++++++++----- .../commands/action/cosmwasm/query/raw/mod.rs | 21 +++- .../action/cosmwasm/query/smart/mod.rs | 7 +- .../src/commands/address_book/show_address.rs | 2 +- cw-orch-cli/src/common.rs | 3 +- 7 files changed, 100 insertions(+), 47 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index aafe64be6..b45517f1e 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -19,8 +19,7 @@ pub struct ExecuteContractCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, - #[interactive_clap(skip_default_input_arg)] - /// Enter message + /// Enter message or filename msg: String, #[interactive_clap(skip_default_input_arg)] /// Input coins @@ -36,10 +35,6 @@ impl ExecuteContractCommands { msg_type::input_msg_type() } - fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { - msg_type::input_msg_or_filename() - } - fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 65a5f47e2..acd737446 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -24,8 +24,7 @@ pub struct InstantiateContractCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, - #[interactive_clap(skip_default_input_arg)] - /// Enter message + /// Enter message or filename msg: String, /// Label for the contract label: String, @@ -45,10 +44,6 @@ impl InstantiateContractCommands { msg_type::input_msg_type() } - fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { - msg_type::input_msg_or_filename() - } - fn input_coins(_context: &CosmosContext) -> color_eyre::eyre::Result> { crate::common::parse_coins() .map(|c| Some(CliCoins(c))) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs index d795c9100..6bd9394cb 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/msg_type/mod.rs @@ -69,17 +69,10 @@ pub fn input_msg_type() -> color_eyre::eyre::Result> { MsgTypeDiscriminants::JsonMsg => Ok(Some(MsgType::JsonMsg)), MsgTypeDiscriminants::Base64Msg => Ok(Some(MsgType::Base64Msg)), MsgTypeDiscriminants::File => Ok(Some(MsgType::File)), - MsgTypeDiscriminants::Editor => Ok(Some(MsgType::File)), + MsgTypeDiscriminants::Editor => Ok(Some(MsgType::Editor)), } } -pub fn input_msg_or_filename() -> color_eyre::eyre::Result> { - let input = inquire::Text::new("Enter message or filename") - .with_help_message("Leave non-file message input empty for EDITOR input later") - .prompt()?; - Ok(Some(input)) -} - pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre::Result> { match msg_type { MsgType::JsonMsg => { @@ -88,18 +81,9 @@ pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre serde_json::to_vec(&message_json).wrap_err("Unexpected error") } - MsgType::Base64Msg => { - let message = match message_or_file.is_empty() { - false => message_or_file, - true => inquire::Editor::new("Enter") - .with_help_message("Base64-encoded string (e.g. eyJmb28iOiJiYXIifQ==)") - .prompt()?, - }; - - crate::common::B64 - .decode(message) - .wrap_err("Failed to decode base64 string") - } + MsgType::Base64Msg => crate::common::B64 + .decode(message_or_file) + .wrap_err("Failed to decode base64 string"), MsgType::File => { let file_path = std::path::PathBuf::from(message_or_file); let msg_bytes = @@ -107,15 +91,83 @@ pub fn msg_bytes(message_or_file: String, msg_type: MsgType) -> color_eyre::eyre Ok(msg_bytes) } MsgType::Editor => { - let message = inquire::Editor::new("Enter message") - .with_predefined_text("{}") - .with_file_extension(".json") - .prompt()?; + let mut prompt = inquire::Editor::new("Enter message"); + if message_or_file.is_empty() { + prompt = prompt + .with_predefined_text("{}") + .with_file_extension(".json"); + } else { + prompt = prompt.with_file_extension(&message_or_file) + }; + let message = prompt.prompt()?; Ok(message.into_bytes()) } } } +#[derive(Debug, EnumDiscriminants, Clone, Copy, clap::ValueEnum)] +#[strum_discriminants(derive(EnumMessage, EnumIter))] +/// How do you want to pass the key arguments? +pub enum KeyType { + #[strum_discriminants(strum(message = "Raw string"))] + /// Raw string (e.g. contract_info) + Raw, + #[strum_discriminants(strum(message = "base64 message"))] + /// Base64-encoded string (e.g. Y29udHJhY3QtaW5mbw==) + Base64, +} + +impl interactive_clap::ToCli for KeyType { + type CliVariant = KeyType; +} + +impl std::str::FromStr for KeyType { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "raw" => Ok(Self::Raw), + "base64" => Ok(Self::Base64), + _ => Err("KeyType: incorrect key type".to_string()), + } + } +} + +impl std::fmt::Display for KeyType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Raw => write!(f, "raw"), + Self::Base64 => write!(f, "base64"), + } + } +} + +impl std::fmt::Display for KeyTypeDiscriminants { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Raw => write!(f, "Raw"), + Self::Base64 => write!(f, "Base64"), + } + } +} + +pub fn input_key_type() -> color_eyre::eyre::Result> { + let variants = KeyTypeDiscriminants::iter().collect::>(); + let selected = Select::new("Select key format", variants).prompt()?; + match selected { + KeyTypeDiscriminants::Raw => Ok(Some(KeyType::Raw)), + KeyTypeDiscriminants::Base64 => Ok(Some(KeyType::Base64)), + } +} + +pub fn key_bytes(key: String, key_type: KeyType) -> color_eyre::eyre::Result> { + match key_type { + KeyType::Raw => Ok(key.into_bytes()), + KeyType::Base64 => crate::common::B64 + .decode(key) + .wrap_err("Failed to decode base64 string"), + } +} + #[cfg(test)] mod test { use super::*; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index 0541595b4..01d6450b9 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -6,7 +6,13 @@ use cw_orch::{ tokio::runtime::Runtime, }; -use crate::{commands::action::CosmosContext, types::CliAddress}; +use crate::{ + commands::action::{ + cosmwasm::msg_type::{self, key_bytes, KeyType}, + CosmosContext, + }, + types::CliAddress, +}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -14,11 +20,19 @@ use crate::{commands::action::CosmosContext, types::CliAddress}; pub struct QueryRawCommands { /// Contract Address or alias from address-book contract: CliAddress, - // TODO: add base-64 option for binary keys + /// Enter key type + #[interactive_clap(skip_default_input_arg)] + key_type: KeyType, /// Enter key key: String, } +impl QueryRawCommands { + fn input_key_type(_context: &CosmosContext) -> color_eyre::eyre::Result> { + msg_type::input_key_type() + } +} + pub struct QueryWasmOutput; impl QueryWasmOutput { @@ -33,6 +47,7 @@ impl QueryWasmOutput { .account_id(chain.chain_info(), &previous_context.global_config)?; let chain_data: ChainRegistryData = chain.into(); + let query_data = key_bytes(scope.key.clone(), scope.key_type)?; let rt = Runtime::new()?; // TODO: replace by no-signer daemon @@ -44,7 +59,7 @@ impl QueryWasmOutput { let resp = client .raw_contract_state(QueryRawContractStateRequest { address: contract_account_id.to_string(), - query_data: scope.key.clone().into_bytes(), + query_data, }) .await?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index ef41a72cd..9fac7d102 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -20,8 +20,7 @@ pub struct QuerySmartCommands { #[interactive_clap(skip_default_input_arg)] /// How do you want to pass the message arguments? msg_type: msg_type::MsgType, - #[interactive_clap(skip_default_input_arg)] - /// Enter message + /// Enter message or filename msg: String, } @@ -31,10 +30,6 @@ impl QuerySmartCommands { ) -> color_eyre::eyre::Result> { msg_type::input_msg_type() } - - fn input_msg(_context: &CosmosContext) -> color_eyre::eyre::Result> { - msg_type::input_msg_or_filename() - } } pub struct QueryWasmOutput; diff --git a/cw-orch-cli/src/commands/address_book/show_address.rs b/cw-orch-cli/src/commands/address_book/show_address.rs index f75fe84b2..42b96839b 100644 --- a/cw-orch-cli/src/commands/address_book/show_address.rs +++ b/cw-orch-cli/src/commands/address_book/show_address.rs @@ -42,7 +42,7 @@ impl ShowAddressOutput { let runtime = Runtime::new()?; let _ = runtime.block_on(show_addr_explorer( chain.chain_info().network_info.id.to_owned(), - &account_id.to_string(), + account_id.as_ref(), )); } None => println!("Address not found"), diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index 960bd9be2..b38e53255 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -44,6 +44,7 @@ pub fn parse_coins() -> InquireResult { let mut coins = cosmwasm_std::Coins::default(); loop { let coin = inquire::Text::new("Add coin to transaction") + .with_help_message("Leave empty to stop adding coins") .with_placeholder("0ucoin") .prompt()?; if !coin.is_empty() { @@ -98,7 +99,7 @@ pub async fn show_addr_explorer(chain_name: String, addr: &str) -> color_eyre::e let Explorers { explorers } = Explorers::fetch(chain_name, None).await?; for explorer in explorers { if let Some(tx_page) = explorer.account_page { - let url = tx_page.replace("${accountAddress}", &addr); + let url = tx_page.replace("${accountAddress}", addr); println!("Explorer: {url}"); break; } From 5079fc27f36977fa897e143af2ba32193b18cd33 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Apr 2024 19:21:50 +0300 Subject: [PATCH 118/135] quick readme fix --- cw-orch-cli/Cargo.toml | 2 +- cw-orch-cli/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 9e38210d2..1c4bc9773 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-orch-cli" -version = "0.2.0" +version = "0.2.1" authors = ["Buckram "] edition.workspace = true license.workspace = true diff --git a/cw-orch-cli/README.md b/cw-orch-cli/README.md index 1b93b804a..92085a6c8 100644 --- a/cw-orch-cli/README.md +++ b/cw-orch-cli/README.md @@ -57,7 +57,7 @@ You can utilize the non-interactive mode for scripting, automated operations, an Example: ```bash -cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms6q698938k529q3shmfl90 contract_info +cw-orch-cli action uni-6 cw query raw juno1czkm9gq96zwwncxusgzruvpuex4wjf4ak7lms6q698938k529q3shmfl90 raw contract_info ``` ### Global optional arguments From 46dc1d4af367d19ee9b9eb507162cb43e08eddfa Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Apr 2024 19:32:31 +0300 Subject: [PATCH 119/135] fix of explorers --- .../src/commands/address_book/show_address.rs | 2 +- .../src/commands/keys/show_address/mod.rs | 6 +---- cw-orch-cli/src/common.rs | 23 ++++++++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/cw-orch-cli/src/commands/address_book/show_address.rs b/cw-orch-cli/src/commands/address_book/show_address.rs index 42b96839b..45e74aa9a 100644 --- a/cw-orch-cli/src/commands/address_book/show_address.rs +++ b/cw-orch-cli/src/commands/address_book/show_address.rs @@ -41,7 +41,7 @@ impl ShowAddressOutput { println!("{account_id}"); let runtime = Runtime::new()?; let _ = runtime.block_on(show_addr_explorer( - chain.chain_info().network_info.id.to_owned(), + chain.chain_info().clone(), account_id.as_ref(), )); } diff --git a/cw-orch-cli/src/commands/keys/show_address/mod.rs b/cw-orch-cli/src/commands/keys/show_address/mod.rs index 6933eba23..2e7c08be5 100644 --- a/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -44,11 +44,7 @@ impl ShowAddressOutput { .await?; let address = daemon.sender(); println!("Your address: {address}"); - let _ = show_addr_explorer( - chain.chain_info().network_info.id.to_owned(), - address.as_str(), - ) - .await; + let _ = show_addr_explorer(chain.chain_info().clone(), address.as_str()).await; color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; Ok(ShowAddressOutput) diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index b38e53255..314b4cd63 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -1,6 +1,6 @@ use crate::{fetch::explorers::Explorers, types::CliLockedChain}; pub use base64::prelude::BASE64_STANDARD as B64; -use cw_orch::daemon::{networks::SUPPORTED_NETWORKS as NETWORKS, Fetchable}; +use cw_orch::daemon::{networks::SUPPORTED_NETWORKS as NETWORKS, ChainInfo, ChainKind, Fetchable}; use inquire::{error::InquireResult, InquireError, Select}; pub fn get_cw_cli_exec_path() -> String { @@ -95,13 +95,20 @@ pub fn parse_expiration() -> InquireResult { Ok(expiration) } -pub async fn show_addr_explorer(chain_name: String, addr: &str) -> color_eyre::eyre::Result<()> { - let Explorers { explorers } = Explorers::fetch(chain_name, None).await?; - for explorer in explorers { - if let Some(tx_page) = explorer.account_page { - let url = tx_page.replace("${accountAddress}", addr); - println!("Explorer: {url}"); - break; +pub async fn show_addr_explorer( + chain_info: ChainInfo<'static>, + addr: &str, +) -> color_eyre::eyre::Result<()> { + // TODO: should be allowed for any type of chain ORC-119 + if let ChainKind::Mainnet = chain_info.kind { + let Explorers { explorers } = + Explorers::fetch(chain_info.network_info.id.to_owned(), None).await?; + for explorer in explorers { + if let Some(tx_page) = explorer.account_page { + let url = tx_page.replace("${accountAddress}", addr); + println!("Explorer: {url}"); + break; + } } } Ok(()) From e37b8639655d7b14d0ee0244bad2a7eeb9892791 Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 12 Apr 2024 19:35:53 +0300 Subject: [PATCH 120/135] versionbump --- cw-orch-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 1c4bc9773..9dbe0d6ca 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-orch-cli" -version = "0.2.1" +version = "0.2.2" authors = ["Buckram "] edition.workspace = true license.workspace = true From 4fbe6b7668e755d0e7763403a02cb60b4e9fc3e7 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 20 Jun 2024 11:05:27 +0300 Subject: [PATCH 121/135] update to newest cw-orch --- cw-orch-cli/Cargo.toml | 5 +++-- .../src/commands/action/asset/query_cw20/mod.rs | 9 +++------ .../src/commands/action/asset/query_native/mod.rs | 9 +++------ .../src/commands/action/cosmwasm/query/raw/mod.rs | 9 +++------ .../commands/action/cosmwasm/query/smart/mod.rs | 9 +++------ .../src/commands/action/cw_ownable/get/mod.rs | 9 +++------ .../commands/action/cw_ownable/transfer/mod.rs | 7 +++++-- cw-orch-cli/src/common.rs | 15 ++++++++------- cw-orch-cli/src/fetch/explorers.rs | 2 +- cw-orch-cli/src/log/mod.rs | 6 ++++-- cw-orch-cli/src/types/address_book.rs | 4 ++-- cw-orch-cli/src/types/chain.rs | 11 +++++++---- cw-orch-cli/src/types/cli_subdir.rs | 2 +- 13 files changed, 46 insertions(+), 51 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 9dbe0d6ca..35cfff082 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-orch-cli" -version = "0.2.2" +version = "0.2.3" authors = ["Buckram "] edition.workspace = true license.workspace = true @@ -10,7 +10,7 @@ description = "Command-line tool for managing Cosmos-based interaction." # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cw-orch = { path = "../cw-orch", features = ["daemon"], version = "0.21" } +cw-orch = { workspace = true, features = ["daemon"] } # Logs pretty_env_logger = { version = "0.5.0" } @@ -22,6 +22,7 @@ cw-utils = "1.0.3" cw20 = { version = "1" } cw-ownable = { version = "0.5.1" } cosmrs = { version = "0.15.0", features = ["cosmwasm", "grpc"] } +ibc-chain-registry = { workspace = true } # Serde serde_json = { workspace = true } diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index f062e9294..1b74672a9 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -1,8 +1,5 @@ use cw20::BalanceResponse; -use cw_orch::{ - daemon::{ChainRegistryData, GrpcChannel}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; use cosmrs::proto::cosmwasm::wasm::v1::{ query_client::QueryClient, QuerySmartContractStateRequest, @@ -38,7 +35,7 @@ impl QueryCw20Output { .address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - let chain_data: ChainRegistryData = chain.into(); + let chain_data: ChainInfoOwned = chain.into(); let msg = serde_json::to_vec(&cw20::Cw20QueryMsg::Balance { address: account_id.to_string(), })?; @@ -47,7 +44,7 @@ impl QueryCw20Output { rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; + GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index ac9d75206..a42f3030c 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -5,10 +5,7 @@ use cosmrs::proto::cosmos::{ }, base::v1beta1::Coin, }; -use cw_orch::{ - daemon::{ChainRegistryData, GrpcChannel}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; use crate::types::{CliAddress, CliSkippable}; @@ -39,12 +36,12 @@ impl QueryNativeOutput { .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - let chain_data: ChainRegistryData = chain.into(); + let chain_data: ChainInfoOwned = chain.into(); let rt = Runtime::new()?; rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; + GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); if let Some(denom) = denom { let response: QueryBalanceResponse = client diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs index 01d6450b9..ff6146b7d 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs @@ -1,10 +1,7 @@ use cosmrs::proto::cosmwasm::wasm::v1::{ query_client::QueryClient, QueryRawContractStateRequest, QueryRawContractStateResponse, }; -use cw_orch::{ - daemon::{ChainRegistryData, GrpcChannel}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; use crate::{ commands::action::{ @@ -46,14 +43,14 @@ impl QueryWasmOutput { .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - let chain_data: ChainRegistryData = chain.into(); + let chain_data: ChainInfoOwned = chain.into(); let query_data = key_bytes(scope.key.clone(), scope.key_type)?; let rt = Runtime::new()?; // TODO: replace by no-signer daemon let resp = rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; + GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs index 9fac7d102..78d94f3b9 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs @@ -1,10 +1,7 @@ use cosmrs::proto::cosmwasm::wasm::v1::{ query_client::QueryClient, QuerySmartContractStateRequest, QuerySmartContractStateResponse, }; -use cw_orch::{ - daemon::{ChainRegistryData, GrpcChannel}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; use crate::{commands::action::CosmosContext, types::CliAddress}; @@ -46,13 +43,13 @@ impl QueryWasmOutput { let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; - let chain_data: ChainRegistryData = chain.into(); + let chain_data: ChainInfoOwned = chain.into(); let rt = Runtime::new()?; // TODO: replace by no-signer daemon let resp = rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; + GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index f1a8d1ef9..5a1375b1c 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -1,7 +1,4 @@ -use cw_orch::{ - daemon::{ChainRegistryData, GrpcChannel}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; use cosmrs::proto::cosmwasm::wasm::v1::{ query_client::QueryClient, QuerySmartContractStateRequest, @@ -33,13 +30,13 @@ impl GetOwnershipOutput { .account_id(chain.chain_info(), &previous_context.global_config)?; let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; - let chain_data: ChainRegistryData = chain.into(); + let chain_data: ChainInfoOwned = chain.into(); // TODO: replace by no-signer daemon let rt = Runtime::new()?; rt.block_on(async { let grpc_channel = - GrpcChannel::connect(&chain_data.apis.grpc, chain_data.chain_id.as_str()).await?; + GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; let mut client = QueryClient::new(grpc_channel); let resp = client diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index 7f65917f6..b0677e8d4 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -91,8 +91,11 @@ impl TransferOwnershipOutput { println!("Successfully transferred ownership, waiting for approval by {new_owner}",); if let Some(seed) = receiver_seed { - let receiver_sender = - cw_orch::daemon::sender::Sender::from_mnemonic(&daemon.state, &seed)?; + let receiver_sender = cw_orch::daemon::sender::Sender::from_mnemonic( + chain.into(), + daemon.channel(), + &seed, + )?; daemon.set_sender(&Wallet::new(receiver_sender)); let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index 314b4cd63..e847a5c67 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -1,6 +1,10 @@ use crate::{fetch::explorers::Explorers, types::CliLockedChain}; pub use base64::prelude::BASE64_STANDARD as B64; -use cw_orch::daemon::{networks::SUPPORTED_NETWORKS as NETWORKS, ChainInfo, ChainKind, Fetchable}; +use cw_orch::{ + daemon::networks::SUPPORTED_NETWORKS as NETWORKS, + environment::{ChainInfo, ChainKind}, +}; +use ibc_chain_registry::fetchable::Fetchable; use inquire::{error::InquireResult, InquireError, Select}; pub fn get_cw_cli_exec_path() -> String { @@ -13,7 +17,7 @@ pub fn select_chain() -> color_eyre::eyre::Result> { .map(|network| { format!( "{} {}({})", - network.network_info.id.to_uppercase(), + network.network_info.chain_name.to_uppercase(), network.kind.to_string().to_uppercase(), network.chain_id ) @@ -95,14 +99,11 @@ pub fn parse_expiration() -> InquireResult { Ok(expiration) } -pub async fn show_addr_explorer( - chain_info: ChainInfo<'static>, - addr: &str, -) -> color_eyre::eyre::Result<()> { +pub async fn show_addr_explorer(chain_info: ChainInfo, addr: &str) -> color_eyre::eyre::Result<()> { // TODO: should be allowed for any type of chain ORC-119 if let ChainKind::Mainnet = chain_info.kind { let Explorers { explorers } = - Explorers::fetch(chain_info.network_info.id.to_owned(), None).await?; + Explorers::fetch(chain_info.network_info.chain_name.to_owned(), None).await?; for explorer in explorers { if let Some(tx_page) = explorer.account_page { let url = tx_page.replace("${accountAddress}", addr); diff --git a/cw-orch-cli/src/fetch/explorers.rs b/cw-orch-cli/src/fetch/explorers.rs index d11f04fb7..2b3697c97 100644 --- a/cw-orch-cli/src/fetch/explorers.rs +++ b/cw-orch-cli/src/fetch/explorers.rs @@ -1,4 +1,4 @@ -use cw_orch::daemon::Fetchable; +use ibc_chain_registry::fetchable::Fetchable; use serde::{Deserialize, Serialize}; use std::path::PathBuf; diff --git a/cw-orch-cli/src/log/mod.rs b/cw-orch-cli/src/log/mod.rs index 1ca8f3159..972816ef3 100644 --- a/cw-orch-cli/src/log/mod.rs +++ b/cw-orch-cli/src/log/mod.rs @@ -1,7 +1,9 @@ use cw_orch::{ - daemon::{ChainInfo, ChainKind, CosmTxResponse, Fetchable}, + daemon::CosmTxResponse, + environment::{ChainInfo, ChainKind}, tokio::runtime::Runtime, }; +use ibc_chain_registry::fetchable::Fetchable; use crate::fetch::explorers::Explorers; @@ -17,7 +19,7 @@ impl LogOutput for CosmTxResponse { let log_explorer_url = || -> cw_orch::anyhow::Result<()> { let rt = Runtime::new()?; let Explorers { explorers } = rt.block_on(Explorers::fetch( - chain_info.network_info.id.to_owned(), + chain_info.network_info.chain_name.to_owned(), None, ))?; for explorer in explorers { diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 2b00d9717..0c9675cee 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -18,7 +18,7 @@ use std::{ use color_eyre::eyre::Context; use cosmrs::AccountId; -use cw_orch::daemon::ChainInfo; +use cw_orch::environment::ChainInfo; use serde_json::{json, Value}; fn address_book_path() -> color_eyre::Result { @@ -291,7 +291,7 @@ pub fn cw_orch_state_contracts( chain: &ChainInfo, deployment_id: &str, ) -> color_eyre::Result> { - let chain_name = chain.network_info.id; + let chain_name = chain.network_info.chain_name; let chain_id = chain.chain_id; let json = read_cw_orch_state()?; diff --git a/cw-orch-cli/src/types/chain.rs b/cw-orch-cli/src/types/chain.rs index 24c85bae7..35e59e412 100644 --- a/cw-orch-cli/src/types/chain.rs +++ b/cw-orch-cli/src/types/chain.rs @@ -1,6 +1,9 @@ use std::str::FromStr; -use cw_orch::daemon::{networks::SUPPORTED_NETWORKS, ChainInfo, ChainRegistryData}; +use cw_orch::{ + daemon::networks::SUPPORTED_NETWORKS, + environment::{ChainInfo, ChainInfoOwned}, +}; #[derive(Default, Debug, Clone, Copy)] pub struct CliLockedChain(usize); @@ -10,14 +13,14 @@ impl CliLockedChain { CliLockedChain(index) } - pub fn chain_info<'a>(&self) -> &ChainInfo<'a> { + pub fn chain_info(&self) -> &ChainInfo { &SUPPORTED_NETWORKS[self.0] } } -impl From for ChainRegistryData { +impl From for ChainInfoOwned { fn from(value: CliLockedChain) -> Self { - SUPPORTED_NETWORKS[value.0].to_owned().into() + SUPPORTED_NETWORKS[value.0].clone().into() } } diff --git a/cw-orch-cli/src/types/cli_subdir.rs b/cw-orch-cli/src/types/cli_subdir.rs index 7f022e49f..536e8ea88 100644 --- a/cw-orch-cli/src/types/cli_subdir.rs +++ b/cw-orch-cli/src/types/cli_subdir.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use cw_orch::environment::default_state_folder; +use cw_orch::env_vars::default_state_folder; pub const CLI_FOLDER: &str = "cli"; From 9bf0175908ff7c67f9eeb3786f38c41b1517f3b3 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 20 Jun 2024 11:27:02 +0300 Subject: [PATCH 122/135] clippy --- cw-orch-cli/src/types/chain.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cw-orch-cli/src/types/chain.rs b/cw-orch-cli/src/types/chain.rs index 35e59e412..2266534cb 100644 --- a/cw-orch-cli/src/types/chain.rs +++ b/cw-orch-cli/src/types/chain.rs @@ -37,9 +37,9 @@ impl FromStr for CliLockedChain { } } -impl ToString for CliLockedChain { - fn to_string(&self) -> String { - SUPPORTED_NETWORKS[self.0].chain_id.to_owned() +impl ::std::fmt::Display for CliLockedChain { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", SUPPORTED_NETWORKS[self.0].chain_id) } } From 7dc6b11c6a925500961d2f3a326384d7d257e51a Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 20 Jun 2024 11:41:15 +0300 Subject: [PATCH 123/135] use daemon bank querier for querying balance --- .../commands/action/asset/query_native/mod.rs | 40 +++---------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index a42f3030c..088417d07 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -42,52 +42,22 @@ impl QueryNativeOutput { rt.block_on(async { let grpc_channel = GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; - let mut client = QueryClient::new(grpc_channel); + let bank = cw_orch::daemon::queriers::Bank::new_async(grpc_channel); if let Some(denom) = denom { - let response: QueryBalanceResponse = client - .balance(QueryBalanceRequest { - address: account_id.to_string(), - denom: denom.clone(), - }) + let balance = bank + ._balance(account_id.to_string(), Some(denom)) .await? - .into_inner(); - let balance = - response - .balance - .map(proto_coin_to_std) - .unwrap_or(cosmwasm_std::Coin { - denom, - amount: Default::default(), - }); + .swap_remove(0); println!("balance: {balance}") } else { - let response: QueryAllBalancesResponse = client - .all_balances(QueryAllBalancesRequest { - address: account_id.to_string(), - pagination: None, - }) - .await? - .into_inner(); - let balances: Vec = response - .balances - .into_iter() - .map(proto_coin_to_std) - .collect(); + let balances = bank._balance(account_id.to_string(), None).await?; // `cosmwasm_std::Coins` have nice display let coins = cosmwasm_std::Coins::try_from(balances).unwrap(); println!("balances: {coins}") } - color_eyre::Result::<(), color_eyre::Report>::Ok(()) })?; Ok(QueryNativeOutput) } } - -fn proto_coin_to_std(proto: Coin) -> cosmwasm_std::Coin { - cosmwasm_std::Coin { - denom: proto.denom, - amount: proto.amount.parse().unwrap(), - } -} From f9b29fad4722e7f121687c406dd4162003a205c3 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 20 Jun 2024 11:43:00 +0300 Subject: [PATCH 124/135] unused cosmrs --- cw-orch-cli/src/commands/action/asset/query_native/mod.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index 088417d07..c19048ccb 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -1,10 +1,3 @@ -use cosmrs::proto::cosmos::{ - bank::v1beta1::{ - query_client::QueryClient, QueryAllBalancesRequest, QueryAllBalancesResponse, - QueryBalanceRequest, QueryBalanceResponse, - }, - base::v1beta1::Coin, -}; use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; use crate::types::{CliAddress, CliSkippable}; From 328a82b329679769078e721eacf8a2514fa9fe01 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 20 Jun 2024 15:19:19 +0300 Subject: [PATCH 125/135] Use Daemon for sending coins --- .../commands/action/asset/send_native/mod.rs | 25 +++---------------- cw-orch-cli/src/types/coins.rs | 6 +++++ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 76ac824dd..65fc5232b 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -1,8 +1,5 @@ use color_eyre::eyre::Context; -use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync}, - tokio::runtime::Runtime, -}; +use cw_orch::{daemon::Daemon, tokio::runtime::Runtime}; use crate::{ log::LogOutput, @@ -50,27 +47,13 @@ impl SendNativeOutput { .account_id(chain.chain_info(), &previous_context.global_config)?; let seed = seed_phrase_for_id(&scope.signer)?; - let coins: Vec = (&scope.coins).try_into()?; + let coins = scope.coins.clone().into(); let rt = Runtime::new()?; - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) - .mnemonic(seed) - .build() - .await?; - - let transfer_msg = cosmrs::bank::MsgSend { - from_address: daemon.sender.pub_addr()?, - to_address, - amount: coins, - }; - - let resp = daemon.sender.commit_tx(vec![transfer_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; + let daemon = Daemon::builder().chain(chain).mnemonic(seed).build()?; + let resp = rt.block_on(daemon.wallet().bank_send(to_address.as_ref(), coins))?; resp.log(chain.chain_info()); Ok(SendNativeOutput) diff --git a/cw-orch-cli/src/types/coins.rs b/cw-orch-cli/src/types/coins.rs index 36df598f4..365b3c049 100644 --- a/cw-orch-cli/src/types/coins.rs +++ b/cw-orch-cli/src/types/coins.rs @@ -18,6 +18,12 @@ impl TryFrom<&CliCoins> for Vec { } } +impl From for Vec { + fn from(value: CliCoins) -> Self { + value.0.into() + } +} + impl std::fmt::Display for CliCoins { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) From 2072aa79edc4b62a0fedd271b4cf83be1523f63d Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 19 Jul 2024 17:40:27 +0300 Subject: [PATCH 126/135] post-merge fixes --- cw-orch-cli/Cargo.toml | 2 +- .../commands/action/asset/send_cw20/mod.rs | 12 ++++------- .../commands/action/asset/send_native/mod.rs | 4 ++-- .../commands/action/cosmwasm/execute/mod.rs | 11 ++++------ .../action/cosmwasm/instantiate/mod.rs | 12 ++++------- .../cosmwasm/query/{raw/mod.rs => raw.rs} | 0 .../cosmwasm/query/{smart/mod.rs => smart.rs} | 0 .../src/commands/action/cosmwasm/store/mod.rs | 12 ++++------- .../commands/action/cw_ownable/accept/mod.rs | 9 ++++----- .../action/cw_ownable/renounce/mod.rs | 9 ++++----- .../action/cw_ownable/transfer/mod.rs | 20 +++++++------------ .../src/commands/keys/show_address/mod.rs | 5 ++--- cw-orch-cli/src/main.rs | 3 ++- 13 files changed, 38 insertions(+), 61 deletions(-) rename cw-orch-cli/src/commands/action/cosmwasm/query/{raw/mod.rs => raw.rs} (100%) rename cw-orch-cli/src/commands/action/cosmwasm/query/{smart/mod.rs => smart.rs} (100%) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index 35cfff082..7d4dc6b4b 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw-orch-cli" -version = "0.2.3" +version = "0.2.4" authors = ["Buckram "] edition.workspace = true license.workspace = true diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index 19a2ec897..3cfcc6032 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -1,6 +1,6 @@ use cosmwasm_std::Uint128; use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync}, + daemon::{CosmTxResponse, DaemonAsync, TxSender}, tokio::runtime::Runtime, }; @@ -57,20 +57,16 @@ impl SendCw20Output { let rt = Runtime::new()?; let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) - .mnemonic(seed) - .build() - .await?; + let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), contract: cw20_account_id, msg, funds: vec![], }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 65fc5232b..63ac554ce 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -51,9 +51,9 @@ impl SendNativeOutput { let rt = Runtime::new()?; - let daemon = Daemon::builder().chain(chain).mnemonic(seed).build()?; + let daemon = Daemon::builder(chain).mnemonic(seed).build()?; - let resp = rt.block_on(daemon.wallet().bank_send(to_address.as_ref(), coins))?; + let resp = rt.block_on(daemon.sender().bank_send(to_address.as_ref(), coins))?; resp.log(chain.chain_info()); Ok(SendNativeOutput) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index b45517f1e..e78c050ca 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -1,4 +1,5 @@ use color_eyre::eyre::Context; +use cw_orch::daemon::TxSender; use cw_orch::{daemon::CosmTxResponse, prelude::DaemonAsync, tokio::runtime::Runtime}; use crate::log::LogOutput; @@ -64,20 +65,16 @@ impl ExecuteWasmOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) - .mnemonic(seed) - .build() - .await?; + let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), contract: contract_account_id, msg, funds: coins, }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index acd737446..37e81f761 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Context; use cw_orch::{ - daemon::CosmTxResponse, + daemon::{CosmTxResponse, TxSender}, prelude::{DaemonAsync, IndexResponse}, tokio::runtime::Runtime, }; @@ -68,14 +68,10 @@ impl InstantiateWasmOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) - .mnemonic(seed) - .build() - .await?; + let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; let exec_msg = cosmrs::cosmwasm::MsgInstantiateContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), admin: scope.admin.clone().0.map(|a| a.parse()).transpose()?, code_id: scope.code_id, label: Some(scope.label.clone()), @@ -83,7 +79,7 @@ impl InstantiateWasmOutput { funds: coins, }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; resp.log(chain.chain_info()); diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs similarity index 100% rename from cw-orch-cli/src/commands/action/cosmwasm/query/raw/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs similarity index 100% rename from cw-orch-cli/src/commands/action/cosmwasm/query/smart/mod.rs rename to cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs diff --git a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index c88f051ce..8b668e1ba 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -1,6 +1,6 @@ use color_eyre::eyre::Context; use cw_orch::{ - daemon::CosmTxResponse, + daemon::{CosmTxResponse, TxSender}, prelude::{DaemonAsync, IndexResponse}, tokio::runtime::Runtime, }; @@ -40,19 +40,15 @@ impl StoreWasmOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) - .mnemonic(seed) - .build() - .await?; + let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; let exec_msg = cosmrs::cosmwasm::MsgStoreCode { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), wasm_byte_code, instantiate_permission: None, }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; resp.log(chain.chain_info()); diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 9da855c6f..436e1034c 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,5 +1,5 @@ use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync}, + daemon::{CosmTxResponse, DaemonAsync, TxSender}, tokio::runtime::Runtime, }; @@ -46,20 +46,19 @@ impl AcceptOwnershipOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) + let daemon = DaemonAsync::builder(chain) .mnemonic(sender_seed) .build() .await?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), contract, msg, funds: vec![], }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; resp.log(chain.chain_info()); diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index 0e78fe738..91658406e 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -1,5 +1,5 @@ use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync}, + daemon::{CosmTxResponse, DaemonAsync, TxSender}, tokio::runtime::Runtime, }; @@ -46,20 +46,19 @@ impl RenounceOwnershipOutput { let rt = Runtime::new()?; let resp = rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) + let daemon = DaemonAsync::builder(chain) .mnemonic(sender_seed) .build() .await?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), contract, msg, funds: vec![], }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; color_eyre::Result::::Ok(resp) })?; resp.log(chain.chain_info()); diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index b0677e8d4..ff24a8f59 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -1,5 +1,5 @@ use cw_orch::{ - daemon::{DaemonAsync, Wallet}, + daemon::{DaemonAsync, TxSender}, tokio::runtime::Runtime, }; @@ -72,40 +72,34 @@ impl TransferOwnershipOutput { let rt = Runtime::new()?; rt.block_on(async { - let mut daemon = DaemonAsync::builder() - .chain(chain) + let daemon = DaemonAsync::builder(chain) .mnemonic(sender_seed) .build() .await?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), contract: contract.clone(), msg, funds: vec![], }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; resp.log(chain.chain_info()); println!("Successfully transferred ownership, waiting for approval by {new_owner}",); if let Some(seed) = receiver_seed { - let receiver_sender = cw_orch::daemon::sender::Sender::from_mnemonic( - chain.into(), - daemon.channel(), - &seed, - )?; - daemon.set_sender(&Wallet::new(receiver_sender)); + let daemon = daemon.rebuild().mnemonic(seed).build().await?; let action = cw_ownable::Action::AcceptOwnership {}; let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender.pub_addr()?, + sender: daemon.sender().account_id(), contract, msg, funds: vec![], }; - let resp = daemon.sender.commit_tx(vec![exec_msg], None).await?; + let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; resp.log(chain.chain_info()); println!("{new_owner} successfully accepted ownership"); } diff --git a/cw-orch-cli/src/commands/keys/show_address/mod.rs b/cw-orch-cli/src/commands/keys/show_address/mod.rs index 2e7c08be5..955594f34 100644 --- a/cw-orch-cli/src/commands/keys/show_address/mod.rs +++ b/cw-orch-cli/src/commands/keys/show_address/mod.rs @@ -37,12 +37,11 @@ impl ShowAddressOutput { let rt = Runtime::new()?; rt.block_on(async { - let daemon = DaemonAsync::builder() - .chain(chain) + let daemon = DaemonAsync::builder(chain) .mnemonic(mnemonic) .build() .await?; - let address = daemon.sender(); + let address = daemon.sender_addr(); println!("Your address: {address}"); let _ = show_addr_explorer(chain.chain_info().clone(), address.as_str()).await; color_eyre::Result::<(), color_eyre::Report>::Ok(()) diff --git a/cw-orch-cli/src/main.rs b/cw-orch-cli/src/main.rs index 325eeddb2..1830dad11 100644 --- a/cw-orch-cli/src/main.rs +++ b/cw-orch-cli/src/main.rs @@ -1,3 +1,4 @@ +use cw_orch::daemon::env::LOGS_ACTIVATION_MESSAGE_ENV_NAME; use cw_orch_cli::{common, TLCommand}; use inquire::ui::{Attributes, RenderConfig, StyleSheet}; @@ -5,7 +6,7 @@ use interactive_clap::{ResultFromCli, ToCliArgs}; fn main() -> color_eyre::Result<()> { // We don't want to see cw-orch logs during cli - std::env::set_var("CW_ORCH_DISABLE_LOGS_ACTIVATION_MESSAGE", "true"); + std::env::set_var(LOGS_ACTIVATION_MESSAGE_ENV_NAME, "false"); let render_config = RenderConfig { prompt: StyleSheet::new().with_attr(Attributes::BOLD), ..Default::default() From 9eb20ded49171eb4362329c7fc74050e7cb49b0b Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 19 Jul 2024 17:40:36 +0300 Subject: [PATCH 127/135] new contract queries --- .../commands/action/cosmwasm/query/code.rs | 29 +++++++++++++++ .../action/cosmwasm/query/contract_info.rs | 35 +++++++++++++++++++ .../src/commands/action/cosmwasm/query/mod.rs | 8 +++++ 3 files changed, 72 insertions(+) create mode 100644 cw-orch-cli/src/commands/action/cosmwasm/query/code.rs create mode 100644 cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs new file mode 100644 index 000000000..6fe410021 --- /dev/null +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs @@ -0,0 +1,29 @@ +use crate::commands::action::CosmosContext; + +use cw_orch::{daemon::DaemonBuilder, environment::ChainInfoOwned, prelude::*}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = QueryCodeOutput)] +pub struct QueryCodeCommands { + /// Enter code id + code_id: u64, +} + +pub struct QueryCodeOutput; + +impl QueryCodeOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + + let chain_data: ChainInfoOwned = chain.into(); + let daemon = DaemonBuilder::new(chain_data.clone()).build_sender(())?; + let code_info = daemon.wasm_querier().code(scope.code_id)?; + println!("{}", serde_json::to_string_pretty(&code_info)?); + + Ok(QueryCodeOutput) + } +} diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs new file mode 100644 index 000000000..95b9bd51e --- /dev/null +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs @@ -0,0 +1,35 @@ +use crate::{commands::action::CosmosContext, types::CliAddress}; + +use cw_orch::{daemon::DaemonBuilder, environment::ChainInfoOwned, prelude::*}; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = CosmosContext)] +#[interactive_clap(output_context = QueryContractInfoOutput)] +pub struct QueryContractInfoCommands { + /// Contract Address or alias from address-book + contract: CliAddress, +} + +pub struct QueryContractInfoOutput; + +impl QueryContractInfoOutput { + fn from_previous_context( + previous_context: CosmosContext, + scope:&::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let chain = previous_context.chain; + let account_id = scope + .contract + .clone() + .account_id(chain.chain_info(), &previous_context.global_config)?; + + let chain_data: ChainInfoOwned = chain.into(); + let daemon = DaemonBuilder::new(chain_data.clone()).build_sender(())?; + let contract_info = daemon + .wasm_querier() + .contract_info(account_id.to_string())?; + println!("{}", serde_json::to_string_pretty(&contract_info)?); + + Ok(QueryContractInfoOutput) + } +} diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs index 7dcc5671a..0c7b89d50 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs @@ -2,6 +2,8 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; use crate::commands::action::CosmosContext; +mod code; +mod contract_info; mod raw; mod smart; @@ -23,4 +25,10 @@ pub enum QueryAction { /// Query wasm raw state #[strum_discriminants(strum(message = "👉 Raw"))] Raw(raw::QueryRawCommands), + /// Query code + #[strum_discriminants(strum(message = "🔢 Code"))] + Code(code::QueryCodeCommands), + /// Query contract info + #[strum_discriminants(strum(message = "🔍 Contract Info"))] + ContractInfo(contract_info::QueryContractInfoCommands), } From cf7836d880049ad87f8605f6123f5439eba56ddc Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 22 Jul 2024 09:12:52 +0300 Subject: [PATCH 128/135] toml format --- Cargo.toml | 26 +++++++++++++------------- cw-orch-daemon/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad94e3156..6e8f3d579 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [workspace] members = [ - "cw-orch", - "cw-orch-cli", - "cw-orch-daemon", - "cw-orch-interchain", - "packages/cw-orch-core", - "packages/cw-orch-mock", - "packages/cw-orch-networks", - "packages/cw-orch-osmosis-test-tube", - "packages/cw-orch-traits", - "contracts/*", - "packages/macros/*", - "packages/interchain/*", + "cw-orch", + "cw-orch-cli", + "cw-orch-daemon", + "cw-orch-interchain", + "packages/cw-orch-core", + "packages/cw-orch-mock", + "packages/cw-orch-networks", + "packages/cw-orch-osmosis-test-tube", + "packages/cw-orch-traits", + "contracts/*", + "packages/macros/*", + "packages/interchain/*", ] resolver = "2" @@ -25,7 +25,7 @@ repository = "https://github.com/AbstractSDK/cw-orchestrator" cw-utils = { version = "1.0.1" } cosmwasm-std = { version = "1.1" } cw-multi-test = { package = "abstract-cw-multi-test", version = "1.0.0", features = [ - "cosmwasm_1_4", + "cosmwasm_1_4", ] } cw20 = { package = "abstract-cw20", version = "1.2.2" } cw20-base = { package = "abstract-cw20-base", version = "1.2.2" } diff --git a/cw-orch-daemon/Cargo.toml b/cw-orch-daemon/Cargo.toml index 221e88109..45357ebd3 100644 --- a/cw-orch-daemon/Cargo.toml +++ b/cw-orch-daemon/Cargo.toml @@ -85,7 +85,7 @@ speculoos = "0.11.0" ctor = "0.2.0" duct = "0.13" mock-contract = { path = "../contracts/mock_contract", features = [ - "interface", + "interface", ] } serial_test = { version = "3.0.0" } From 42c490d103f0e9e306ef8a8db27e8ae317425bd2 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 4 Sep 2024 21:40:23 +0300 Subject: [PATCH 129/135] upgrade cw-orch-cli to 0.25 cw-orch --- cw-orch-cli/Cargo.toml | 8 +-- cw-orch-cli/src/commands/action/asset/mod.rs | 8 +-- .../commands/action/asset/query_cw20/mod.rs | 42 ++++-------- .../commands/action/asset/query_native/mod.rs | 39 +++++------ .../commands/action/asset/send_cw20/mod.rs | 39 ++++------- .../commands/action/asset/send_native/mod.rs | 15 +++-- .../commands/action/cosmwasm/execute/mod.rs | 40 ++++++------ .../action/cosmwasm/instantiate/mod.rs | 36 +++++------ .../src/commands/action/cosmwasm/mod.rs | 8 +-- .../commands/action/cosmwasm/query/code.rs | 6 +- .../action/cosmwasm/query/contract_info.rs | 11 ++-- .../src/commands/action/cosmwasm/query/mod.rs | 4 +- .../src/commands/action/cosmwasm/query/raw.rs | 34 +++------- .../commands/action/cosmwasm/query/smart.rs | 33 +++------- .../src/commands/action/cosmwasm/store/mod.rs | 47 ++++++++------ .../commands/action/cw_ownable/accept/mod.rs | 36 ++++------- .../src/commands/action/cw_ownable/get/mod.rs | 35 +++------- .../src/commands/action/cw_ownable/mod.rs | 6 +- .../action/cw_ownable/renounce/mod.rs | 36 ++++------- .../action/cw_ownable/transfer/mod.rs | 64 +++++++------------ cw-orch-cli/src/commands/action/mod.rs | 8 +-- .../commands/address_book/fetch_cw_orch.rs | 4 +- cw-orch-cli/src/commands/address_book/mod.rs | 8 +-- cw-orch-cli/src/fetch/explorers.rs | 2 + cw-orch-cli/src/types/address_book.rs | 14 ++-- cw-orch-cli/src/types/chain.rs | 14 +++- cw-orch-daemon/src/state.rs | 1 - 27 files changed, 235 insertions(+), 363 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index fd5457ca9..ace88552c 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -18,10 +18,10 @@ async-trait = { version = "0.1" } # Cosmos cosmwasm-std = { workspace = true } -cw-utils = "1.0.3" -cw20 = { version = "1" } -cw-ownable = { version = "0.5.1" } -cosmrs = { version = "0.15.0", features = ["cosmwasm", "grpc"] } +cw-utils = "2.0.0" +cw20 = { version = "2.0" } +cw-ownable = { version = "2.0.0" } +cosmrs = { workspace = true, features = ["cosmwasm", "grpc"] } ibc-chain-registry = { workspace = true } # Serde diff --git a/cw-orch-cli/src/commands/action/asset/mod.rs b/cw-orch-cli/src/commands/action/asset/mod.rs index 6cac98067..de6f113a1 100644 --- a/cw-orch-cli/src/commands/action/asset/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/mod.rs @@ -1,12 +1,12 @@ +use super::CosmosContext; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + mod query_cw20; mod query_native; mod send_cw20; mod send_native; -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - -use super::CosmosContext; - #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(context = CosmosContext)] pub struct AssetCommands { diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index 1b74672a9..33f291b38 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -1,14 +1,10 @@ -use cw20::BalanceResponse; -use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; - -use cosmrs::proto::cosmwasm::wasm::v1::{ - query_client::QueryClient, QuerySmartContractStateRequest, -}; - use crate::types::CliAddress; use super::CosmosContext; +use cw20::BalanceResponse; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryCw20Output)] @@ -35,29 +31,15 @@ impl QueryCw20Output { .address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - let chain_data: ChainInfoOwned = chain.into(); - let msg = serde_json::to_vec(&cw20::Cw20QueryMsg::Balance { - address: account_id.to_string(), - })?; - - let rt = Runtime::new()?; - - rt.block_on(async { - let grpc_channel = - GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; - let mut client = QueryClient::new(grpc_channel); - - let resp = client - .smart_contract_state(QuerySmartContractStateRequest { - address: cw20_account_id.to_string(), - query_data: msg, - }) - .await?; - let parsed_output: BalanceResponse = serde_json::from_slice(&resp.into_inner().data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); - - color_eyre::Result::<(), color_eyre::Report>::Ok(()) - })?; + let daemon = chain.daemon_querier()?; + + let balance: BalanceResponse = daemon.query( + &(cw20::Cw20QueryMsg::Balance { + address: account_id.to_string(), + }), + &Addr::unchecked(cw20_account_id), + )?; + println!("{}", serde_json::to_string_pretty(&balance)?); Ok(QueryCw20Output) } diff --git a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs index c19048ccb..bb81ef069 100644 --- a/cw-orch-cli/src/commands/action/asset/query_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_native/mod.rs @@ -1,9 +1,9 @@ -use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; - use crate::types::{CliAddress, CliSkippable}; use super::CosmosContext; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryNativeOutput)] @@ -28,28 +28,19 @@ impl QueryNativeOutput { .address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - - let chain_data: ChainInfoOwned = chain.into(); - let rt = Runtime::new()?; - - rt.block_on(async { - let grpc_channel = - GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; - let bank = cw_orch::daemon::queriers::Bank::new_async(grpc_channel); - if let Some(denom) = denom { - let balance = bank - ._balance(account_id.to_string(), Some(denom)) - .await? - .swap_remove(0); - println!("balance: {balance}") - } else { - let balances = bank._balance(account_id.to_string(), None).await?; - // `cosmwasm_std::Coins` have nice display - let coins = cosmwasm_std::Coins::try_from(balances).unwrap(); - println!("balances: {coins}") - } - color_eyre::Result::<(), color_eyre::Report>::Ok(()) - })?; + let addr = Addr::unchecked(account_id); + + let daemon = chain.daemon_querier()?; + + if let Some(denom) = denom { + let balance = daemon.balance(&addr, Some(denom))?.swap_remove(0); + println!("balance: {balance}") + } else { + let balances = daemon.balance(&addr, None)?; + // `cosmwasm_std::Coins` have nice display + let coins = cosmwasm_std::Coins::try_from(balances).unwrap(); + println!("balances: {coins}") + } Ok(QueryNativeOutput) } diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index 3cfcc6032..ac09a1067 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -1,9 +1,3 @@ -use cosmwasm_std::Uint128; -use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync, TxSender}, - tokio::runtime::Runtime, -}; - use crate::{ log::LogOutput, types::{keys::seed_phrase_for_id, CliAddress}, @@ -11,6 +5,9 @@ use crate::{ use super::CosmosContext; +use cosmwasm_std::Uint128; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = SendCw20Output)] @@ -47,28 +44,18 @@ impl SendCw20Output { .cw20_address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let cw20_addr = Addr::unchecked(cw20_account_id); let seed = seed_phrase_for_id(&scope.signer)?; - let cw20_msg = cw20::Cw20ExecuteMsg::Transfer { - recipient: to_address_account_id.to_string(), - amount: Uint128::new(scope.amount), - }; - let msg = serde_json::to_vec(&cw20_msg)?; - let rt = Runtime::new()?; - - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; - - let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender().account_id(), - contract: cw20_account_id, - msg, - funds: vec![], - }; - - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; + let daemon = chain.daemon(seed)?; + let resp = daemon.execute( + &cw20::Cw20ExecuteMsg::Transfer { + recipient: to_address_account_id.to_string(), + amount: Uint128::new(scope.amount), + }, + &[], + &cw20_addr, + )?; resp.log(chain.chain_info()); diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 63ac554ce..9efb86b62 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -1,6 +1,3 @@ -use color_eyre::eyre::Context; -use cw_orch::{daemon::Daemon, tokio::runtime::Runtime}; - use crate::{ log::LogOutput, types::{keys::seed_phrase_for_id, CliAddress, CliCoins}, @@ -8,6 +5,9 @@ use crate::{ use super::CosmosContext; +use color_eyre::eyre::Context; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = SendNativeOutput)] @@ -45,15 +45,16 @@ impl SendNativeOutput { .to_address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let to_address = Addr::unchecked(to_address); let seed = seed_phrase_for_id(&scope.signer)?; let coins = scope.coins.clone().into(); - let rt = Runtime::new()?; - - let daemon = Daemon::builder(chain).mnemonic(seed).build()?; + let daemon = chain.daemon(seed)?; - let resp = rt.block_on(daemon.sender().bank_send(to_address.as_ref(), coins))?; + let resp = daemon + .rt_handle + .block_on(daemon.sender().bank_send(&to_address, coins))?; resp.log(chain.chain_info()); Ok(SendNativeOutput) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index e78c050ca..35411fb3d 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -1,14 +1,14 @@ -use color_eyre::eyre::Context; -use cw_orch::daemon::TxSender; -use cw_orch::{daemon::CosmTxResponse, prelude::DaemonAsync, tokio::runtime::Runtime}; - -use crate::log::LogOutput; -use crate::types::keys::seed_phrase_for_id; -use crate::types::CliAddress; -use crate::{commands::action::CosmosContext, types::CliCoins}; +use crate::{ + commands::action::CosmosContext, + log::LogOutput, + types::{keys::seed_phrase_for_id, CliAddress, CliCoins}, +}; use super::msg_type; +use color_eyre::eyre::Context; +use cw_orch::daemon::TxSender; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = ExecuteWasmOutput)] @@ -63,20 +63,16 @@ impl ExecuteWasmOutput { let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; - let rt = Runtime::new()?; - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; - - let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender().account_id(), - contract: contract_account_id, - msg, - funds: coins, - }; - - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; + let daemon = chain.daemon(seed)?; + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { + sender: daemon.sender().account_id(), + contract: contract_account_id, + msg, + funds: coins, + }; + let resp = daemon + .rt_handle + .block_on(daemon.sender().commit_tx(vec![exec_msg], None))?; resp.log(chain.chain_info()); diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 37e81f761..003c09bfb 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -1,10 +1,3 @@ -use color_eyre::eyre::Context; -use cw_orch::{ - daemon::{CosmTxResponse, TxSender}, - prelude::{DaemonAsync, IndexResponse}, - tokio::runtime::Runtime, -}; - use crate::{ commands::action::CosmosContext, log::LogOutput, @@ -13,6 +6,9 @@ use crate::{ use super::msg_type; +use color_eyre::eyre::Context; +use cw_orch::{daemon::TxSender, prelude::*}; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = InstantiateWasmOutput)] @@ -66,22 +62,20 @@ impl InstantiateWasmOutput { let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; - let rt = Runtime::new()?; - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; + let daemon = chain.daemon(seed)?; - let exec_msg = cosmrs::cosmwasm::MsgInstantiateContract { - sender: daemon.sender().account_id(), - admin: scope.admin.clone().0.map(|a| a.parse()).transpose()?, - code_id: scope.code_id, - label: Some(scope.label.clone()), - msg, - funds: coins, - }; + let init_msg = cosmrs::cosmwasm::MsgInstantiateContract { + sender: daemon.sender().account_id(), + admin: scope.admin.clone().0.map(|a| a.parse()).transpose()?, + code_id: scope.code_id, + label: Some(scope.label.clone()), + msg, + funds: coins, + }; - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; + let resp = daemon + .rt_handle + .block_on(daemon.sender().commit_tx(vec![init_msg], None))?; resp.log(chain.chain_info()); let address = resp.instantiated_contract_address()?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs index b7ee29205..02fbf8a15 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/mod.rs @@ -1,13 +1,13 @@ +use super::CosmosContext; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + mod execute; mod instantiate; pub mod msg_type; mod query; mod store; -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - -use super::CosmosContext; - #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(context = CosmosContext)] pub struct CwCommands { diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs index 6fe410021..8f039ef71 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/code.rs @@ -1,6 +1,6 @@ use crate::commands::action::CosmosContext; -use cw_orch::{daemon::DaemonBuilder, environment::ChainInfoOwned, prelude::*}; +use cw_orch::prelude::*; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -19,8 +19,8 @@ impl QueryCodeOutput { ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let chain_data: ChainInfoOwned = chain.into(); - let daemon = DaemonBuilder::new(chain_data.clone()).build_sender(())?; + let daemon = chain.daemon_querier()?; + let code_info = daemon.wasm_querier().code(scope.code_id)?; println!("{}", serde_json::to_string_pretty(&code_info)?); diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs index 95b9bd51e..88f2c520a 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs @@ -1,6 +1,6 @@ use crate::{commands::action::CosmosContext, types::CliAddress}; -use cw_orch::{daemon::DaemonBuilder, environment::ChainInfoOwned, prelude::*}; +use cw_orch::prelude::*; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -22,12 +22,11 @@ impl QueryContractInfoOutput { .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let addr = Addr::unchecked(account_id); - let chain_data: ChainInfoOwned = chain.into(); - let daemon = DaemonBuilder::new(chain_data.clone()).build_sender(())?; - let contract_info = daemon - .wasm_querier() - .contract_info(account_id.to_string())?; + let daemon = chain.daemon_querier()?; + + let contract_info = daemon.wasm_querier().contract_info(&addr)?; println!("{}", serde_json::to_string_pretty(&contract_info)?); Ok(QueryContractInfoOutput) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs index 0c7b89d50..7e300a7e3 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/mod.rs @@ -1,7 +1,7 @@ -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - use crate::commands::action::CosmosContext; +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + mod code; mod contract_info; mod raw; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs index ff6146b7d..63922360e 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs @@ -1,8 +1,3 @@ -use cosmrs::proto::cosmwasm::wasm::v1::{ - query_client::QueryClient, QueryRawContractStateRequest, QueryRawContractStateResponse, -}; -use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; - use crate::{ commands::action::{ cosmwasm::msg_type::{self, key_bytes, KeyType}, @@ -11,6 +6,8 @@ use crate::{ types::CliAddress, }; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryWasmOutput)] @@ -42,30 +39,15 @@ impl QueryWasmOutput { .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - - let chain_data: ChainInfoOwned = chain.into(); + let contract_addr = Addr::unchecked(contract_account_id); let query_data = key_bytes(scope.key.clone(), scope.key_type)?; - let rt = Runtime::new()?; - // TODO: replace by no-signer daemon - let resp = rt.block_on(async { - let grpc_channel = - GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; - let mut client = QueryClient::new(grpc_channel); - - let resp = client - .raw_contract_state(QueryRawContractStateRequest { - address: contract_account_id.to_string(), - query_data, - }) - .await?; - - color_eyre::Result::::Ok( - resp.into_inner(), - ) - })?; + let daemon = chain.daemon_querier()?; - let parsed_output: Option = serde_json::from_slice(&resp.data)?; + let resp_data = daemon + .wasm_querier() + .raw_query(&contract_addr, query_data)?; + let parsed_output: Option = serde_json::from_slice(&resp_data)?; let output = parsed_output.unwrap_or_default(); println!("{}", serde_json::to_string_pretty(&output)?); diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs index 78d94f3b9..c7b126eb3 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs @@ -1,12 +1,9 @@ -use cosmrs::proto::cosmwasm::wasm::v1::{ - query_client::QueryClient, QuerySmartContractStateRequest, QuerySmartContractStateResponse, -}; -use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; - use crate::{commands::action::CosmosContext, types::CliAddress}; use super::super::msg_type; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = QueryWasmOutput)] @@ -40,29 +37,15 @@ impl QueryWasmOutput { .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - + let contract_addr = Addr::unchecked(contract_account_id); let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; - let chain_data: ChainInfoOwned = chain.into(); - - let rt = Runtime::new()?; - // TODO: replace by no-signer daemon - let resp = rt.block_on(async { - let grpc_channel = - GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; - let mut client = QueryClient::new(grpc_channel); + let daemon = chain.daemon_querier()?; - let resp = client - .smart_contract_state(QuerySmartContractStateRequest { - address: contract_account_id.to_string(), - query_data: msg, - }) - .await?; - color_eyre::Result::::Ok( - resp.into_inner(), - ) - })?; - let parsed_output: Option = serde_json::from_slice(&resp.data)?; + let resp_data = daemon + .rt_handle + .block_on(daemon.wasm_querier()._contract_state(&contract_addr, msg))?; + let parsed_output: Option = serde_json::from_slice(&resp_data)?; let output = parsed_output.unwrap_or_default(); println!("{}", serde_json::to_string_pretty(&output)?); diff --git a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index 8b668e1ba..9ece13a55 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -1,11 +1,7 @@ -use color_eyre::eyre::Context; -use cw_orch::{ - daemon::{CosmTxResponse, TxSender}, - prelude::{DaemonAsync, IndexResponse}, - tokio::runtime::Runtime, -}; +use crate::{commands::action::CosmosContext, types::keys::seed_phrase_for_id}; -use crate::{commands::action::CosmosContext, log::LogOutput, types::keys::seed_phrase_for_id}; +use color_eyre::eyre::Context; +use cw_orch::{daemon::TxSender, prelude::*}; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -38,24 +34,33 @@ impl StoreWasmOutput { scope.wasm_path.0.display() ))?; - let rt = Runtime::new()?; - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder(chain).mnemonic(seed).build().await?; - - let exec_msg = cosmrs::cosmwasm::MsgStoreCode { - sender: daemon.sender().account_id(), - wasm_byte_code, - instantiate_permission: None, - }; - - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; - resp.log(chain.chain_info()); + let daemon = chain.daemon(seed)?; + let upload_msg = cosmrs::cosmwasm::MsgStoreCode { + sender: daemon.sender().account_id(), + wasm_byte_code, + instantiate_permission: None, + }; + let resp = daemon + .rt_handle + .block_on(daemon.sender().commit_tx(vec![upload_msg], None))?; let code_id = resp.uploaded_code_id().unwrap(); println!("code_id: {code_id}"); Ok(StoreWasmOutput) } } + +// TODO: the dream here to use Uploadable instead +// fn uploadable_from_path(wasm_path: WasmPath) -> impl Uploadable { +// struct Placeholder { +// wasm_path: WasmPath, +// } +// impl Uploadable for Placeholder { +// fn wasm(_chain: &ChainInfoOwned) -> WasmPath { +// // having &self.wasm_path instead would solve the issue +// wasm_path +// } +// } +// Placeholder { wasm_path } +// } diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index 436e1034c..a80ddcf49 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -1,8 +1,3 @@ -use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync, TxSender}, - tokio::runtime::Runtime, -}; - use crate::{ commands::action::CosmosContext, log::LogOutput, @@ -11,6 +6,8 @@ use crate::{ use super::ContractExecuteMsg; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = AcceptOwnershipOutput)] @@ -35,32 +32,21 @@ impl AcceptOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract = scope + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - - let sender_seed = seed_phrase_for_id(&scope.signer)?; + let contract_addr = Addr::unchecked(contract_account_id); + let seed = seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::AcceptOwnership {}; - let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; - - let rt = Runtime::new()?; - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder(chain) - .mnemonic(sender_seed) - .build() - .await?; - let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender().account_id(), - contract, - msg, - funds: vec![], - }; + let daemon = chain.daemon(seed)?; - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; + let resp = daemon.execute( + &ContractExecuteMsg::UpdateOwnership(action), + &[], + &contract_addr, + )?; resp.log(chain.chain_info()); Ok(AcceptOwnershipOutput) diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index 5a1375b1c..7cdab214a 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -1,13 +1,9 @@ -use cw_orch::{daemon::GrpcChannel, environment::ChainInfoOwned, tokio::runtime::Runtime}; - -use cosmrs::proto::cosmwasm::wasm::v1::{ - query_client::QueryClient, QuerySmartContractStateRequest, -}; - use crate::{commands::action::CosmosContext, types::CliAddress}; use super::ContractQueryMsg; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = GetOwnershipOutput)] @@ -28,27 +24,14 @@ impl GetOwnershipOutput { .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let contract_addr = Addr::unchecked(contract_account_id); + + let daemon = chain.daemon_querier()?; - let msg = serde_json::to_vec(&ContractQueryMsg::Ownership {})?; - let chain_data: ChainInfoOwned = chain.into(); - - // TODO: replace by no-signer daemon - let rt = Runtime::new()?; - rt.block_on(async { - let grpc_channel = - GrpcChannel::connect(&chain_data.grpc_urls, chain_data.chain_id.as_str()).await?; - let mut client = QueryClient::new(grpc_channel); - - let resp = client - .smart_contract_state(QuerySmartContractStateRequest { - address: contract_account_id.to_string(), - query_data: msg, - }) - .await?; - let parsed_output: serde_json::Value = serde_json::from_slice(&resp.into_inner().data)?; - println!("{}", serde_json::to_string_pretty(&parsed_output)?); - color_eyre::Result::<(), color_eyre::Report>::Ok(()) - })?; + let output: serde_json::Value = daemon + .wasm_querier() + .smart_query(&contract_addr, &ContractQueryMsg::Ownership {})?; + println!("{}", serde_json::to_string_pretty(&output)?); Ok(GetOwnershipOutput) } diff --git a/cw-orch-cli/src/commands/action/cw_ownable/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs index f8661784c..61d53faf1 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs @@ -1,15 +1,15 @@ +use crate::commands::action::CosmosContext; + use serde::Serialize; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::commands::action::CosmosContext; - mod accept; mod get; mod renounce; mod transfer; // Helper enum to serialize execute -#[derive(Serialize)] +#[derive(Serialize, Debug)] #[serde(rename_all = "snake_case")] enum ContractExecuteMsg { UpdateOwnership(cw_ownable::Action), diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index 91658406e..bb06502c9 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -1,8 +1,3 @@ -use cw_orch::{ - daemon::{CosmTxResponse, DaemonAsync, TxSender}, - tokio::runtime::Runtime, -}; - use crate::{ commands::action::CosmosContext, log::LogOutput, @@ -11,6 +6,8 @@ use crate::{ use super::ContractExecuteMsg; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = RenounceOwnershipOutput)] @@ -35,32 +32,21 @@ impl RenounceOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract = scope + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - - let sender_seed = seed_phrase_for_id(&scope.signer)?; + let contract_addr = Addr::unchecked(contract_account_id); + let seed = seed_phrase_for_id(&scope.signer)?; let action = cw_ownable::Action::RenounceOwnership {}; - let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; - - let rt = Runtime::new()?; - let resp = rt.block_on(async { - let daemon = DaemonAsync::builder(chain) - .mnemonic(sender_seed) - .build() - .await?; - let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender().account_id(), - contract, - msg, - funds: vec![], - }; + let daemon = chain.daemon(seed)?; - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - color_eyre::Result::::Ok(resp) - })?; + let resp = daemon.execute( + &ContractExecuteMsg::UpdateOwnership(action), + &[], + &contract_addr, + )?; resp.log(chain.chain_info()); Ok(RenounceOwnershipOutput) diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index ff24a8f59..410f8d139 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -1,8 +1,3 @@ -use cw_orch::{ - daemon::{DaemonAsync, TxSender}, - tokio::runtime::Runtime, -}; - use crate::{ commands::action::CosmosContext, common::parse_expiration, @@ -12,6 +7,8 @@ use crate::{ use super::ContractExecuteMsg; +use cw_orch::prelude::*; + #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] #[interactive_clap(output_context = TransferOwnershipOutput)] @@ -48,16 +45,17 @@ impl TransferOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let contract = scope + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let contract_addr = Addr::unchecked(contract_account_id); let new_owner = scope .new_owner .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; - let sender_seed = seed_phrase_for_id(&scope.signer)?; + let seed = seed_phrase_for_id(&scope.signer)?; let receiver_seed = scope .new_signer .0 @@ -68,43 +66,27 @@ impl TransferOwnershipOutput { new_owner: new_owner.to_string(), expiry: Some(scope.expiration.0), }; - let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; - let rt = Runtime::new()?; - rt.block_on(async { - let daemon = DaemonAsync::builder(chain) - .mnemonic(sender_seed) - .build() - .await?; - - let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender().account_id(), - contract: contract.clone(), - msg, - funds: vec![], - }; - - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; + let daemon = chain.daemon(seed)?; + let resp = daemon.execute( + &ContractExecuteMsg::UpdateOwnership(action), + &[], + &contract_addr, + )?; + resp.log(chain.chain_info()); + println!("Successfully transferred ownership, waiting for approval by {new_owner}",); + if let Some(seed) = receiver_seed { + let daemon = daemon.rebuild().mnemonic(seed).build()?; + let action = cw_ownable::Action::AcceptOwnership {}; + let resp = daemon.execute( + &ContractExecuteMsg::UpdateOwnership(action), + &[], + &contract_addr, + )?; resp.log(chain.chain_info()); - println!("Successfully transferred ownership, waiting for approval by {new_owner}",); - - if let Some(seed) = receiver_seed { - let daemon = daemon.rebuild().mnemonic(seed).build().await?; - let action = cw_ownable::Action::AcceptOwnership {}; - let msg = serde_json::to_vec(&ContractExecuteMsg::UpdateOwnership(action))?; - let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { - sender: daemon.sender().account_id(), - contract, - msg, - funds: vec![], - }; - let resp = daemon.sender().commit_tx(vec![exec_msg], None).await?; - resp.log(chain.chain_info()); - println!("{new_owner} successfully accepted ownership"); - } - color_eyre::Result::<(), color_eyre::Report>::Ok(()) - })?; + println!("{new_owner} successfully accepted ownership"); + } Ok(TransferOwnershipOutput) } diff --git a/cw-orch-cli/src/commands/action/mod.rs b/cw-orch-cli/src/commands/action/mod.rs index 1a5938f5f..c92d3343e 100644 --- a/cw-orch-cli/src/commands/action/mod.rs +++ b/cw-orch-cli/src/commands/action/mod.rs @@ -1,10 +1,10 @@ -mod asset; -mod cosmwasm; -mod cw_ownable; +use crate::{types::CliLockedChain, GlobalConfig}; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; -use crate::{types::CliLockedChain, GlobalConfig}; +mod asset; +mod cosmwasm; +mod cw_ownable; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = GlobalConfig)] diff --git a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs index 2f633ee98..0c3e9a0d5 100644 --- a/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs +++ b/cw-orch-cli/src/commands/address_book/fetch_cw_orch.rs @@ -1,11 +1,11 @@ use std::str::FromStr; -use strum::IntoEnumIterator; - use crate::types::address_book::{self, cw_orch_state_contracts, CW_ORCH_STATE_FILE_DAMAGED_ERROR}; use super::AddresBookContext; +use strum::IntoEnumIterator; + #[derive(Debug, strum::EnumDiscriminants, strum::Display, Clone, clap::ValueEnum)] #[strum_discriminants(derive(strum::EnumMessage, strum::EnumIter))] pub enum AliasNameStrategy { diff --git a/cw-orch-cli/src/commands/address_book/mod.rs b/cw-orch-cli/src/commands/address_book/mod.rs index ad21e208b..485e500e7 100644 --- a/cw-orch-cli/src/commands/address_book/mod.rs +++ b/cw-orch-cli/src/commands/address_book/mod.rs @@ -1,12 +1,12 @@ +use crate::{types::CliLockedChain, GlobalConfig}; + +use strum::{EnumDiscriminants, EnumIter, EnumMessage}; + mod add_address; mod fetch_cw_orch; mod remove_address; mod show_address; -use strum::{EnumDiscriminants, EnumIter, EnumMessage}; - -use crate::{types::CliLockedChain, GlobalConfig}; - #[derive(Clone, Debug)] pub struct AddresBookContext { pub global_config: GlobalConfig, diff --git a/cw-orch-cli/src/fetch/explorers.rs b/cw-orch-cli/src/fetch/explorers.rs index 2b3697c97..0f61879a6 100644 --- a/cw-orch-cli/src/fetch/explorers.rs +++ b/cw-orch-cli/src/fetch/explorers.rs @@ -18,6 +18,8 @@ pub struct Explorer { } impl Fetchable for Explorers { + const DESC: &'static str = "Getting explorers list"; + fn path(resource: &str) -> PathBuf { [resource, "chain.json"].iter().collect() } diff --git a/cw-orch-cli/src/types/address_book.rs b/cw-orch-cli/src/types/address_book.rs index 0c9675cee..1e7d5750d 100644 --- a/cw-orch-cli/src/types/address_book.rs +++ b/cw-orch-cli/src/types/address_book.rs @@ -296,19 +296,21 @@ pub fn cw_orch_state_contracts( let json = read_cw_orch_state()?; - let Some(chain_state) = json.get(chain_name) else { - return Err(color_eyre::eyre::eyre!("State is empty for {chain_name}")); + let chain_state = if let Some(chain_state) = json.get(chain_name) { + // In case old state + // TODO: should be able to remove in the future + chain_state + } else { + &json }; let Some(chain_id_state) = chain_state.get(chain_id) else { - return Err(color_eyre::eyre::eyre!( - "State is empty for {chain_name}.{chain_id}" - )); + return Err(color_eyre::eyre::eyre!("State is empty for {chain_id}")); }; let Some(deployment) = chain_id_state.get(deployment_id) else { return Err(color_eyre::eyre::eyre!( - "State is empty for {chain_name}.{chain_id}.{deployment_id}" + "State is empty for {chain_id}.{deployment_id}" )); }; diff --git a/cw-orch-cli/src/types/chain.rs b/cw-orch-cli/src/types/chain.rs index 2266534cb..35530b767 100644 --- a/cw-orch-cli/src/types/chain.rs +++ b/cw-orch-cli/src/types/chain.rs @@ -1,7 +1,9 @@ use std::str::FromStr; use cw_orch::{ - daemon::networks::SUPPORTED_NETWORKS, + daemon::{ + networks::SUPPORTED_NETWORKS, senders::QueryOnlyDaemon, Daemon, DaemonBuilder, DaemonError, + }, environment::{ChainInfo, ChainInfoOwned}, }; @@ -16,6 +18,16 @@ impl CliLockedChain { pub fn chain_info(&self) -> &ChainInfo { &SUPPORTED_NETWORKS[self.0] } + + pub fn daemon(&self, seed: String) -> Result { + DaemonBuilder::new(SUPPORTED_NETWORKS[self.0].clone()) + .mnemonic(seed) + .build() + } + + pub fn daemon_querier(&self) -> Result { + DaemonBuilder::new(SUPPORTED_NETWORKS[self.0].clone()).build_sender(()) + } } impl From for ChainInfoOwned { diff --git a/cw-orch-daemon/src/state.rs b/cw-orch-daemon/src/state.rs index 80d88fcfe..2eaf3c965 100644 --- a/cw-orch-daemon/src/state.rs +++ b/cw-orch-daemon/src/state.rs @@ -60,7 +60,6 @@ pub enum DaemonStateFile { impl DaemonState { /// Creates a new state from the given chain data and deployment id. - /// Attempts to connect to any of the provided gRPC endpoints. pub fn new( mut json_file_path: String, chain_data: &Arc, From 69c4d80512d10d24166d5cf49a8b5679c00a2c17 Mon Sep 17 00:00:00 2001 From: Buckram Date: Wed, 4 Sep 2024 21:50:34 +0300 Subject: [PATCH 130/135] small formatting --- .../commands/action/asset/query_cw20/mod.rs | 6 ++++- .../commands/action/asset/send_cw20/mod.rs | 4 +++- .../commands/action/asset/send_native/mod.rs | 4 ++-- .../commands/action/cosmwasm/execute/mod.rs | 9 ++++---- .../action/cosmwasm/instantiate/mod.rs | 3 ++- .../action/cosmwasm/query/contract_info.rs | 1 + .../src/commands/action/cosmwasm/query/raw.rs | 2 ++ .../commands/action/cosmwasm/query/smart.rs | 2 ++ .../src/commands/action/cosmwasm/store/mod.rs | 2 +- .../commands/action/cw_ownable/accept/mod.rs | 5 ++-- .../src/commands/action/cw_ownable/get/mod.rs | 1 + .../action/cw_ownable/renounce/mod.rs | 5 ++-- .../action/cw_ownable/transfer/mod.rs | 23 +++++++++++-------- 13 files changed, 43 insertions(+), 24 deletions(-) diff --git a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs index 33f291b38..5466ce50a 100644 --- a/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/query_cw20/mod.rs @@ -23,21 +23,25 @@ impl QueryCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let cw20_account_id = scope .cw20_address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let cw20_addr = Addr::unchecked(cw20_account_id); + let account_id = scope .address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let daemon = chain.daemon_querier()?; let balance: BalanceResponse = daemon.query( &(cw20::Cw20QueryMsg::Balance { address: account_id.to_string(), }), - &Addr::unchecked(cw20_account_id), + &cw20_addr, )?; println!("{}", serde_json::to_string_pretty(&balance)?); diff --git a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs index ac09a1067..085e08a04 100644 --- a/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_cw20/mod.rs @@ -36,10 +36,12 @@ impl SendCw20Output { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let to_address_account_id = scope .to_address .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; + let cw20_account_id = scope .cw20_address .clone() @@ -48,6 +50,7 @@ impl SendCw20Output { let seed = seed_phrase_for_id(&scope.signer)?; let daemon = chain.daemon(seed)?; + let resp = daemon.execute( &cw20::Cw20ExecuteMsg::Transfer { recipient: to_address_account_id.to_string(), @@ -56,7 +59,6 @@ impl SendCw20Output { &[], &cw20_addr, )?; - resp.log(chain.chain_info()); Ok(SendCw20Output) diff --git a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs index 9efb86b62..e3cc01d97 100644 --- a/cw-orch-cli/src/commands/action/asset/send_native/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/send_native/mod.rs @@ -41,6 +41,8 @@ impl SendNativeOutput { scope: &::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let coins = scope.coins.clone().into(); + let to_address = scope .to_address .clone() @@ -48,8 +50,6 @@ impl SendNativeOutput { let to_address = Addr::unchecked(to_address); let seed = seed_phrase_for_id(&scope.signer)?; - let coins = scope.coins.clone().into(); - let daemon = chain.daemon(seed)?; let resp = daemon diff --git a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs index 35411fb3d..d7411e950 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/execute/mod.rs @@ -54,16 +54,18 @@ impl ExecuteWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; + let coins = (&scope.coins).try_into()?; + let contract_account_id = scope .contract_addr .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let seed = seed_phrase_for_id(&scope.signer)?; - let coins = (&scope.coins).try_into()?; - let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; - let daemon = chain.daemon(seed)?; + let exec_msg = cosmrs::cosmwasm::MsgExecuteContract { sender: daemon.sender().account_id(), contract: contract_account_id, @@ -73,7 +75,6 @@ impl ExecuteWasmOutput { let resp = daemon .rt_handle .block_on(daemon.sender().commit_tx(vec![exec_msg], None))?; - resp.log(chain.chain_info()); Ok(ExecuteWasmOutput) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs index 003c09bfb..94090a7c0 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/instantiate/mod.rs @@ -58,10 +58,11 @@ impl InstantiateWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let seed = seed_phrase_for_id(&scope.signer)?; + let coins = (&scope.coins).try_into()?; let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; + let seed = seed_phrase_for_id(&scope.signer)?; let daemon = chain.daemon(seed)?; let init_msg = cosmrs::cosmwasm::MsgInstantiateContract { diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs index 88f2c520a..f6c6c8832 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/contract_info.rs @@ -18,6 +18,7 @@ impl QueryContractInfoOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let account_id = scope .contract .clone() diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs index 63922360e..ddc748cf8 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/raw.rs @@ -35,11 +35,13 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let contract_addr = Addr::unchecked(contract_account_id); + let query_data = key_bytes(scope.key.clone(), scope.key_type)?; let daemon = chain.daemon_querier()?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs b/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs index c7b126eb3..bc34a9dae 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/query/smart.rs @@ -33,11 +33,13 @@ impl QueryWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let contract_addr = Addr::unchecked(contract_account_id); + let msg = msg_type::msg_bytes(scope.msg.clone(), scope.msg_type.clone())?; let daemon = chain.daemon_querier()?; diff --git a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index 9ece13a55..d799baa85 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -28,12 +28,12 @@ impl StoreWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let seed = seed_phrase_for_id(&scope.signer)?; let wasm_byte_code = std::fs::read(&scope.wasm_path).wrap_err(format!( "Failed to open or read the file: {}", scope.wasm_path.0.display() ))?; + let seed = seed_phrase_for_id(&scope.signer)?; let daemon = chain.daemon(seed)?; let upload_msg = cosmrs::cosmwasm::MsgStoreCode { diff --git a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs index a80ddcf49..65d43ead4 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/accept/mod.rs @@ -32,16 +32,17 @@ impl AcceptOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let contract_addr = Addr::unchecked(contract_account_id); - let seed = seed_phrase_for_id(&scope.signer)?; - let action = cw_ownable::Action::AcceptOwnership {}; + let seed = seed_phrase_for_id(&scope.signer)?; let daemon = chain.daemon(seed)?; + let action = cw_ownable::Action::AcceptOwnership {}; let resp = daemon.execute( &ContractExecuteMsg::UpdateOwnership(action), &[], diff --git a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs index 7cdab214a..fe2885e9d 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/get/mod.rs @@ -20,6 +20,7 @@ impl GetOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope .contract .clone() diff --git a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs index bb06502c9..b92b0a398 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/renounce/mod.rs @@ -32,16 +32,17 @@ impl RenounceOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let contract_addr = Addr::unchecked(contract_account_id); - let seed = seed_phrase_for_id(&scope.signer)?; - let action = cw_ownable::Action::RenounceOwnership {}; + let seed = seed_phrase_for_id(&scope.signer)?; let daemon = chain.daemon(seed)?; + let action = cw_ownable::Action::RenounceOwnership {}; let resp = daemon.execute( &ContractExecuteMsg::UpdateOwnership(action), &[], diff --git a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs index 410f8d139..03cc728ff 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/transfer/mod.rs @@ -45,29 +45,25 @@ impl TransferOwnershipOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; + let contract_account_id = scope .contract .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let contract_addr = Addr::unchecked(contract_account_id); + let new_owner = scope .new_owner .clone() .account_id(chain.chain_info(), &previous_context.global_config)?; let seed = seed_phrase_for_id(&scope.signer)?; - let receiver_seed = scope - .new_signer - .0 - .as_deref() - .map(seed_phrase_for_id) - .transpose()?; + let daemon = chain.daemon(seed)?; + let action = cw_ownable::Action::TransferOwnership { new_owner: new_owner.to_string(), expiry: Some(scope.expiration.0), }; - - let daemon = chain.daemon(seed)?; let resp = daemon.execute( &ContractExecuteMsg::UpdateOwnership(action), &[], @@ -76,8 +72,15 @@ impl TransferOwnershipOutput { resp.log(chain.chain_info()); println!("Successfully transferred ownership, waiting for approval by {new_owner}",); - if let Some(seed) = receiver_seed { - let daemon = daemon.rebuild().mnemonic(seed).build()?; + let maybe_receiver_seed = scope + .new_signer + .0 + .as_deref() + .map(seed_phrase_for_id) + .transpose()?; + if let Some(receiver_seed) = maybe_receiver_seed { + let daemon = daemon.rebuild().mnemonic(receiver_seed).build()?; + let action = cw_ownable::Action::AcceptOwnership {}; let resp = daemon.execute( &ContractExecuteMsg::UpdateOwnership(action), From 8689d72ffe1e058726bc00c98955934f267a7e4d Mon Sep 17 00:00:00 2001 From: Buckram Date: Mon, 9 Sep 2024 15:38:42 +0300 Subject: [PATCH 131/135] cli doc formatting --- docs/src/cli/index.md | 6 +++--- docs/src/cli/keys.md | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/docs/src/cli/index.md b/docs/src/cli/index.md index 35f825c7b..152890fcd 100644 --- a/docs/src/cli/index.md +++ b/docs/src/cli/index.md @@ -1,6 +1,6 @@ # Orchestrator Command Line Interface (CLI) -Currently, each chain has its own CLI based on wasmd, which are incompatible with each other. With this in mind, we created cw-orch-cli. cw-orchestrator allows for easy chain switching, which is essential for cross-chain solutions. +Currently, each chain has its own CLI based on wasmd, which are incompatible with each other. With this in mind, we created cw-orch-cli. cw-orchestrator allows for easy chain switching, which is essential for cross-chain solutions. ## Prerequisites @@ -18,6 +18,6 @@ cargo install cw-orch-cli Supported features of cw-orch-cli: - **[Keys management](./keys.md)** - - Add, show or remove key from/into keyring + - Add, show or remove key for the CLI -Feel free to request new features by [opening an issue](https://github.com/AbstractSDK/cw-orchestrator/issues/new)! \ No newline at end of file +Feel free to request new features by [opening an issue](https://github.com/AbstractSDK/cw-orchestrator/issues/new)! diff --git a/docs/src/cli/keys.md b/docs/src/cli/keys.md index 78885664a..4039366e6 100644 --- a/docs/src/cli/keys.md +++ b/docs/src/cli/keys.md @@ -3,26 +3,33 @@ To sign transactions, you need to have a stored key in the keyring. This is currently the only way to sign transactions, feel free to request other signing methods. ## Safety + The keys are kept in an underlying platform-specific secure store(keyring) as seeds. To support different derivation paths we can't save it as key pair ## Features -#### Add key +### Add key + +Add key command saves provided or generated seed to the keyring: -Add key command saves provided or generated seed to the keyring - Generate new random seed : `cw-orch-cli key add [NAME] new` - Recover from seed phrase: `cw-orch-cli key add [NAME] from-seed` - - This command will give you prompt -#### Show seed of saved key + - This command will give you prompt for your mnemonic + +### Show seed of saved key + +Show seed command loads saved seed phrase from the keyring and outputs it: -Show seed command loads saved seed phrase from keyring and outputs it - Shows seed phrase of the key: `cw-orch-cli key show [NAME]` #### Show address -Show address command generates public address for this key on chosen network +Show address command generates public address for this key on chosen network: + - Show address: `cw-orch-cli key show-address [NAME] [CHAIN_ID]` + #### Remove key -Remove key command deletes entry of provided key-id from the keyring -- Removes key: `cw-orch-cli key remove [NAME]` \ No newline at end of file +Remove key command deletes entry of provided key-id from the keyring: + +- Remove saved key: `cw-orch-cli key remove [NAME]` From a7730c73e3380ecd0841df20f3ab696818ff9da5 Mon Sep 17 00:00:00 2001 From: Buckram Date: Thu, 26 Sep 2024 15:35:41 +0300 Subject: [PATCH 132/135] update cosmos action docs --- cw-orch-cli/src/commands/action/asset/mod.rs | 2 +- .../src/commands/action/cw_ownable/mod.rs | 2 +- docs/src/cli/cosmos_action.md | 47 +++++++++++++++++++ docs/src/cli/index.md | 4 +- docs/src/cli/keys.md | 4 +- 5 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 docs/src/cli/cosmos_action.md diff --git a/cw-orch-cli/src/commands/action/asset/mod.rs b/cw-orch-cli/src/commands/action/asset/mod.rs index de6f113a1..171f7482b 100644 --- a/cw-orch-cli/src/commands/action/asset/mod.rs +++ b/cw-orch-cli/src/commands/action/asset/mod.rs @@ -22,7 +22,7 @@ pub enum AssetAction { /// Native or factory coin send #[strum_discriminants(strum(message = "Send native coins"))] SendNative(send_native::SendNativeCommands), - /// Native or factory coin transfer + /// Cw20 coin transfer #[strum_discriminants(strum(message = "Send cw20 coin"))] SendCw20(send_cw20::Cw20TransferCommands), /// Native or factory coins query diff --git a/cw-orch-cli/src/commands/action/cw_ownable/mod.rs b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs index 61d53faf1..e615770c1 100644 --- a/cw-orch-cli/src/commands/action/cw_ownable/mod.rs +++ b/cw-orch-cli/src/commands/action/cw_ownable/mod.rs @@ -40,7 +40,7 @@ pub enum CwOwnableAction { /// Accept pending ownership #[strum_discriminants(strum(message = "✅ Accept pending ownership."))] Accept(accept::AcceptOwnership), - // /// Renounce pending ownership + /// Renounce pending ownership #[strum_discriminants(strum(message = "🚫 Renounce pending ownership"))] Renounce(renounce::RenounceOwnership), /// Get current ownership diff --git a/docs/src/cli/cosmos_action.md b/docs/src/cli/cosmos_action.md new file mode 100644 index 000000000..5a89c400b --- /dev/null +++ b/docs/src/cli/cosmos_action.md @@ -0,0 +1,47 @@ +# Cosmos Action + +This command allows to perform an action on cosmos chain, if this action requires signing given [Signer](./keys.md) would be used + +## Chain id + +For doing any cosmos action chain id is needed, so it have to be provided before selecting any of the subcommand + +## Features + +### CosmWasm Action + +Interact with CosmWasm smart contract + +- Store smart contract: `cw-orch-cli action [CHAIN_ID] cw store [WASM_PATH] [SIGNER]` +- Instantiate smart contract: `cw-orch-cli action [CHAIN_ID] cw instantiate [CODE_ID] [MSG_TYPE] [MSG] [LABEL] [ADMIN] [COINS] [SIGNER]` +- Execute smart contract method: `cw-orch-cli action [CHAIN_ID] cw execute [OPTIONS] [CONTRACT_ADDR] [MSG_TYPE] [MSG] [COINS] [SIGNER]` +- Query smart contract: + - Smart query: `cw-orch-cli action [CHAIN_ID] cw query smart [OPTIONS] [CONTRACT] [MSG_TYPE] [MSG]` + - Raw state query: `cw-orch-cli action [CHAIN_ID] cw query raw [OPTIONS] [CONTRACT] [KEY_TYPE] [KEY]` + - [KEY_TYPE] supports 2 types: `raw`, `base64`(for non-human-readable keys) + +### Asset Action + +Send or query assets on cosmos chain + +- Send native or factory coin: `cw-orch-cli action [CHAIN_ID] asset send-native [OPTIONS] [COINS] [TO_ADDRESS] [SIGNER]` +- Send cw20 coin: `cw-orch-cli action [CHAIN_ID] asset send-cw20 [OPTIONS] [CW20_ADDRESS] [AMOUNT] [TO_ADDRESS] [SIGNER]` +- Query native or factory coin balance: `cw-orch-cli action [CHAIN_ID] asset query-native [OPTIONS] [DENOM] [ADDRESS]` + - For querying all balances use empty string ("") instead of [DENOM] +- Query cw20 balance: `cw-orch-cli action [CHAIN_ID] asset query-cw20 [OPTIONS] [CW20_ADDRESS] [ADDRESS]` + +### CW-Ownable Action + +Interact with cw-ownable controller on CosmWasm smart contract + +- Propose to transfer contract ownership to another address: `cw-orch-cli action [CHAIN_ID] cw-ownable transfer [OPTIONS] [CONTRACT] [NEW_OWNER] [EXPIRATION] [SIGNER] [NEW_SIGNER]` + - [EXPIRATION] supports three variants: `never`, `height:{block_height}`, `time:{time_nanos}` + - If you cannot sign [NEW_SIGNER] use empty string("") instead +- Accept pending ownership: `cw-orch-cli action [CHAIN_ID] cw-ownable accept [OPTIONS] [CONTRACT] [SIGNER]` +- Renounce pending ownership: `cw-orch-cli action [CHAIN_ID] cw-ownable renounce [OPTIONS] [CONTRACT] [SIGNER]` +- Get current ownership: `cw-orch-cli action [CHAIN_ID] cw-ownable get [OPTIONS] [CONTRACT]` + +#### Arguments reference + +- [MSG_TYPE] is a format for provided `[MSG]`, possible values: `json-msg`, `base64-msg`, `file`, `editor` +- [COINS] formatted and parsed same way as `cosmwasm_std::Coins`, for example: "5ujunox,15utestx" diff --git a/docs/src/cli/index.md b/docs/src/cli/index.md index 152890fcd..26afdb3ad 100644 --- a/docs/src/cli/index.md +++ b/docs/src/cli/index.md @@ -17,7 +17,7 @@ cargo install cw-orch-cli Supported features of cw-orch-cli: -- **[Keys management](./keys.md)** - - Add, show or remove key for the CLI +- **[Keys management](./keys.md)**: Add, show or remove key for the CLI +- **[Action](./cosmos_action.md)**: Perform cosmos action Feel free to request new features by [opening an issue](https://github.com/AbstractSDK/cw-orchestrator/issues/new)! diff --git a/docs/src/cli/keys.md b/docs/src/cli/keys.md index 4039366e6..e90c5f847 100644 --- a/docs/src/cli/keys.md +++ b/docs/src/cli/keys.md @@ -22,13 +22,13 @@ Show seed command loads saved seed phrase from the keyring and outputs it: - Shows seed phrase of the key: `cw-orch-cli key show [NAME]` -#### Show address +### Show address Show address command generates public address for this key on chosen network: - Show address: `cw-orch-cli key show-address [NAME] [CHAIN_ID]` -#### Remove key +### Remove key Remove key command deletes entry of provided key-id from the keyring: From 930b65a44efffeed977e0f4941490d0a6fdd01fc Mon Sep 17 00:00:00 2001 From: Buckram Date: Fri, 27 Sep 2024 10:20:33 +0300 Subject: [PATCH 133/135] bump interactive clap --- cw-orch-cli/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cw-orch-cli/Cargo.toml b/cw-orch-cli/Cargo.toml index ace88552c..3fd84ed81 100644 --- a/cw-orch-cli/Cargo.toml +++ b/cw-orch-cli/Cargo.toml @@ -30,8 +30,8 @@ serde = { workspace = true } base64 = { version = "0.22.1" } # Interactive clap -interactive-clap = "0.2.8" -interactive-clap-derive = "0.2.8" +interactive-clap = "0.3.0" +interactive-clap-derive = "0.3.0" clap = { version = "4.0.18", features = ["derive"] } color-eyre = { version = "0.6" } strum = { version = "0.24", features = ["derive"] } From ecca95d1f565fd82e4ad9ca9eae3ab8fde4d37e9 Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 8 Oct 2024 11:32:07 +0300 Subject: [PATCH 134/135] wasm upload fixed --- .../src/commands/action/cosmwasm/store/mod.rs | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs index d799baa85..8f2cc79b6 100644 --- a/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs +++ b/cw-orch-cli/src/commands/action/cosmwasm/store/mod.rs @@ -1,7 +1,6 @@ use crate::{commands::action::CosmosContext, types::keys::seed_phrase_for_id}; -use color_eyre::eyre::Context; -use cw_orch::{daemon::TxSender, prelude::*}; +use cw_orch::prelude::*; #[derive(Debug, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(input_context = CosmosContext)] @@ -28,39 +27,17 @@ impl StoreWasmOutput { scope:&::InteractiveClapContextScope, ) -> color_eyre::eyre::Result { let chain = previous_context.chain; - let wasm_byte_code = std::fs::read(&scope.wasm_path).wrap_err(format!( - "Failed to open or read the file: {}", - scope.wasm_path.0.display() - ))?; + let wasm_path = WasmPath::new(&scope.wasm_path)?; let seed = seed_phrase_for_id(&scope.signer)?; let daemon = chain.daemon(seed)?; - let upload_msg = cosmrs::cosmwasm::MsgStoreCode { - sender: daemon.sender().account_id(), - wasm_byte_code, - instantiate_permission: None, - }; let resp = daemon .rt_handle - .block_on(daemon.sender().commit_tx(vec![upload_msg], None))?; + .block_on(daemon.sender().upload_wasm(wasm_path))?; let code_id = resp.uploaded_code_id().unwrap(); println!("code_id: {code_id}"); Ok(StoreWasmOutput) } } - -// TODO: the dream here to use Uploadable instead -// fn uploadable_from_path(wasm_path: WasmPath) -> impl Uploadable { -// struct Placeholder { -// wasm_path: WasmPath, -// } -// impl Uploadable for Placeholder { -// fn wasm(_chain: &ChainInfoOwned) -> WasmPath { -// // having &self.wasm_path instead would solve the issue -// wasm_path -// } -// } -// Placeholder { wasm_path } -// } From f7549cd449775a1f1fca907a52a872e1d852e8dc Mon Sep 17 00:00:00 2001 From: Buckram Date: Tue, 15 Oct 2024 16:35:45 +0300 Subject: [PATCH 135/135] remove rejected todos --- cw-orch-cli/src/common.rs | 1 - cw-orch-cli/src/log/mod.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/cw-orch-cli/src/common.rs b/cw-orch-cli/src/common.rs index e847a5c67..62a24d2d3 100644 --- a/cw-orch-cli/src/common.rs +++ b/cw-orch-cli/src/common.rs @@ -100,7 +100,6 @@ pub fn parse_expiration() -> InquireResult { } pub async fn show_addr_explorer(chain_info: ChainInfo, addr: &str) -> color_eyre::eyre::Result<()> { - // TODO: should be allowed for any type of chain ORC-119 if let ChainKind::Mainnet = chain_info.kind { let Explorers { explorers } = Explorers::fetch(chain_info.network_info.chain_name.to_owned(), None).await?; diff --git a/cw-orch-cli/src/log/mod.rs b/cw-orch-cli/src/log/mod.rs index 972816ef3..cf1e1b258 100644 --- a/cw-orch-cli/src/log/mod.rs +++ b/cw-orch-cli/src/log/mod.rs @@ -14,7 +14,6 @@ pub trait LogOutput { impl LogOutput for CosmTxResponse { fn log(&self, chain_info: &ChainInfo) { println!("Transaction hash: {}", self.txhash); - // TODO: should be allowed for any type of chain ORC-119 if let ChainKind::Mainnet = chain_info.kind { let log_explorer_url = || -> cw_orch::anyhow::Result<()> { let rt = Runtime::new()?;