From a519658432737e367f0c61fc47ed5bfd718dd40f Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 15:50:22 +0000 Subject: [PATCH 01/20] first commit --- Cargo.toml | 1 + .../rust-cosmos-broadcaster-client/Cargo.toml | 21 +++++++++ demos/rust-cosmos-broadcaster-client/plan.txt | 13 ++++++ .../src/main.rs | 45 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 demos/rust-cosmos-broadcaster-client/Cargo.toml create mode 100644 demos/rust-cosmos-broadcaster-client/plan.txt create mode 100644 demos/rust-cosmos-broadcaster-client/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 9b2a13c7ef..a8cd37821d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ members = [ "common/topology", "common/types", "common/wasm-utils", + "demos/rust-cosmos-broadcaster-client", "explorer-api", "gateway", "gateway/gateway-requests", diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml new file mode 100644 index 0000000000..04f47ab582 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "rust-cosmos-broadcaster-client" +version = "0.1.0" +authors.workspace = true +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.0", features = ["derive"] } +nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] } +nym-network-defaults = { path = "../../common/network-defaults" } +async-trait = { workspace = true, optional = true } +bip39 = { workspace = true, features = ["rand"], optional = true } +cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true } + +[dev-dependencies] +bip39 = { workspace = true } +cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32"] } +tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] } +ts-rs = "6.1.2" diff --git a/demos/rust-cosmos-broadcaster-client/plan.txt b/demos/rust-cosmos-broadcaster-client/plan.txt new file mode 100644 index 0000000000..3ff129e190 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/plan.txt @@ -0,0 +1,13 @@ +Plan: +* rewrite ts cosmos broadcaster SP in rust +* create simple rust binary for client cli use with 2 functions: + * use standard CLI method - cf. NymCLI + * getSequence() for offline signing + * submitTx() for sending tx thru mixnet to SP for broadcasting + +* rust server code - communicates with chain + * sdk + * nym validator client - broadcast client, gets sequence + submits tx +* rust client code - communicates with server via mixnet + * sdk + * nym validator client - offline signer diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs new file mode 100644 index 0000000000..1fb28154a5 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -0,0 +1,45 @@ +use clap::{CommandFactory, Parser, Subcommand, Args}; +use nym_validator_client::nyxd::CosmWasmClient; +use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; +use nym_validator_client::signing::tx_signer::TxSigner; +use nym_validator_client::signing::SignerData; +/* use cosmrs::bank::MsgSend; +use cosmrs::rpc::{self, HttpClient}; +use cosmrs::tx::Msg; +use cosmrs::{tx, AccountId, Coin, Denom}; +*/ + +#[derive(Debug, Parser)] +#[clap(name = "cosmos tx broadcaster ")] +#[clap(about = "binary which accepts pre-signed txs from the mixnet and broadcasts them to a cosmos sdk chain ")] +struct Cli { + #[clap(subcommand)] + command: Option, +} + +#[derive(Debug, Subcommand)] +enum Commands { + /// Reverses a string + Reverse(Reverse), + /// Inspects a string + Inspect(Inspect), +} + +#[derive(Debug, Args)] +struct Reverse { + /// The string to reverse + string: Option, +} + +#[derive(Debug, Args)] +struct Inspect { + /// The string to inspect + string: Option, + #[arg(short = 'd', long = "digits")] + only_digits: bool, +} + + +fn main() { + println!("Hello, world!"); +} From 79ee623a1a519a09f42371fe9f38ce927a6bf1ad Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 17:06:20 +0000 Subject: [PATCH 02/20] fixed bad cosmrs import --- demos/rust-cosmos-broadcaster-client/Cargo.toml | 2 +- demos/rust-cosmos-broadcaster-client/src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml index 04f47ab582..725d1af734 100644 --- a/demos/rust-cosmos-broadcaster-client/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -12,7 +12,7 @@ nym-validator-client = { path = "../../common/client-libs/validator-client", fea nym-network-defaults = { path = "../../common/network-defaults" } async-trait = { workspace = true, optional = true } bip39 = { workspace = true, features = ["rand"], optional = true } -cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true } +cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"] } [dev-dependencies] bip39 = { workspace = true } diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 1fb28154a5..552a9da0fc 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -3,11 +3,11 @@ use nym_validator_client::nyxd::CosmWasmClient; use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; use nym_validator_client::signing::tx_signer::TxSigner; use nym_validator_client::signing::SignerData; -/* use cosmrs::bank::MsgSend; +use cosmrs::bank::MsgSend; use cosmrs::rpc::{self, HttpClient}; use cosmrs::tx::Msg; use cosmrs::{tx, AccountId, Coin, Denom}; -*/ + #[derive(Debug, Parser)] #[clap(name = "cosmos tx broadcaster ")] From dfce9ced1df68fd79e2addff31c6567ab53bfdb3 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 21:17:29 +0000 Subject: [PATCH 03/20] scaffold of offlineSign() --- .../rust-cosmos-broadcaster-client/Cargo.toml | 7 +- .../rust-cosmos-broadcaster-client/README.md | 3 + .../src/commands/commands.rs | 71 +++++++++++++++++++ .../src/commands/mod.rs | 1 + .../src/main.rs | 71 +++++++++++-------- 5 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 demos/rust-cosmos-broadcaster-client/README.md create mode 100644 demos/rust-cosmos-broadcaster-client/src/commands/commands.rs create mode 100644 demos/rust-cosmos-broadcaster-client/src/commands/mod.rs diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml index 725d1af734..b1c4c341b2 100644 --- a/demos/rust-cosmos-broadcaster-client/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -11,11 +11,8 @@ clap = { version = "4.0", features = ["derive"] } nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] } nym-network-defaults = { path = "../../common/network-defaults" } async-trait = { workspace = true, optional = true } -bip39 = { workspace = true, features = ["rand"], optional = true } +bip39 = { workspace = true, features = ["rand"] } cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"] } - -[dev-dependencies] -bip39 = { workspace = true } -cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32"] } tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] } ts-rs = "6.1.2" + diff --git a/demos/rust-cosmos-broadcaster-client/README.md b/demos/rust-cosmos-broadcaster-client/README.md new file mode 100644 index 0000000000..dff78945d5 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/README.md @@ -0,0 +1,3 @@ +cosmos broadcaster client code - sign txs offline and send thru the mixnet! + +heavily pulling from the offline_signing.rs example file in the validator client code (s/o Jon for writing top examples) \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs new file mode 100644 index 0000000000..6625b31187 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -0,0 +1,71 @@ +use cosmrs::bip32::secp256k1::elliptic_curve::generic_array::sequence; +use nym_validator_client::nyxd::CosmWasmClient; +use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; +use nym_validator_client::signing::tx_signer::TxSigner; +use nym_validator_client::signing::SignerData; +use cosmrs::bank::MsgSend; +use cosmrs::rpc::{self, HttpClient}; +use cosmrs::tx::Msg; +use cosmrs::{tx, AccountId, Coin, Denom}; +use bip39; + +pub async fn offline_sign() -> Vec { + + // TODO load most of this from config file, take address and mnemonic from function args, take address and mnemonic from function args. in V2 take chain-id and tx-type as well + let prefix = "n"; + let denom: Denom = "unym".parse().unwrap(); + let signer_mnemonic: bip39::Mnemonic = "".parse().unwrap(); + let validator = "https://qwerty-validator.qa.nymte.ch"; + let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap(); + + let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, signer_mnemonic); + let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone(); + + // local 'client' ONLY signing messages + let tx_signer = TxSigner::new(signer); + + // possibly remote client that doesn't do ANY signing + // (only broadcasts + queries for sequence numbers) + let broadcaster = HttpClient::new(validator).unwrap(); + + // get signer information + let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); + let chain_id = broadcaster.get_chain_id().await.unwrap(); + let signer_data = SignerData::new_from_sequence_response(sequence_response, chain_id); + + // create (and sign) the send message + let amount = vec![Coin { + denom: denom.clone(), + amount: 12345u32.into(), + }]; + + let send_msg = MsgSend { + from_address: signer_address.clone(), + to_address: to_address.clone(), + amount, + } + .to_any() + .unwrap(); + + let memo = "example memo"; + let fee = tx::Fee::from_amount_and_gas( + Coin { + denom, + amount: 2500u32.into(), + }, + 100000, + ); + + let tx_raw = tx_signer + .sign_direct(&signer_address, vec![send_msg], fee, memo, signer_data) + .unwrap(); + + // TODO return this from function + let tx_bytes = tx_raw.to_bytes().unwrap(); + + tx_bytes + + +} + + diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs b/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs new file mode 100644 index 0000000000..6be336ee9f --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs @@ -0,0 +1 @@ +pub mod commands; \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 552a9da0fc..46e245ab5e 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,17 +1,20 @@ use clap::{CommandFactory, Parser, Subcommand, Args}; -use nym_validator_client::nyxd::CosmWasmClient; -use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; -use nym_validator_client::signing::tx_signer::TxSigner; -use nym_validator_client::signing::SignerData; -use cosmrs::bank::MsgSend; -use cosmrs::rpc::{self, HttpClient}; -use cosmrs::tx::Msg; -use cosmrs::{tx, AccountId, Coin, Denom}; +// use cosmrs::bip32::secp256k1::elliptic_curve::generic_array::sequence; +// use nym_validator_client::nyxd::CosmWasmClient; +// use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; +// use nym_validator_client::signing::tx_signer::TxSigner; +// use nym_validator_client::signing::SignerData; +// use cosmrs::bank::MsgSend; +// use cosmrs::rpc::{self, HttpClient}; +// use cosmrs::tx::Msg; +// use cosmrs::{tx, AccountId, Coin, Denom}; +// use bip39; +mod commands; #[derive(Debug, Parser)] -#[clap(name = "cosmos tx broadcaster ")] -#[clap(about = "binary which accepts pre-signed txs from the mixnet and broadcasts them to a cosmos sdk chain ")] +#[clap(name = "nym cosmos tx signer ")] +#[clap(about = "binary with which users can perform offline signing and transmission of signed tx to broadcaster via the mixnet ")] struct Cli { #[clap(subcommand)] command: Option, @@ -19,27 +22,39 @@ struct Cli { #[derive(Debug, Subcommand)] enum Commands { - /// Reverses a string - Reverse(Reverse), - /// Inspects a string - Inspect(Inspect), + /// sign a transaction offline + OfflineSignTx(OfflineSignTx), + /// send signed tx to SP for broadcast + SendTx(SendTx) +} + +#[derive(Debug, Clone, Args)] +struct OfflineSignTx { + /// some random info for testing + string: String, } #[derive(Debug, Args)] -struct Reverse { - /// The string to reverse - string: Option, +struct SendTx { + /// the address of the nym service to send yr signed tx + sp_address: String // TODO replace with mixnet address type } -#[derive(Debug, Args)] -struct Inspect { - /// The string to inspect - string: Option, - #[arg(short = 'd', long = "digits")] - only_digits: bool, -} +#[tokio::main] +async fn main() { + + let cli = Cli::parse(); - -fn main() { - println!("Hello, world!"); -} + match &cli.command { + Some(Commands::OfflineSignTx(string)) => { + let tx_bytes = commands::commands::offline_sign(); + // TODO parse future + // println!("{}", parsed.iter().format(", ")); + println!("end {:?}", string); + } + Some(Commands::SendTx(sp_address)) => { + todo!(); + } + None => {} + } +} \ No newline at end of file From 301482bfe4160395e5bfd0c3369b32c536b995ec Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 21:30:09 +0000 Subject: [PATCH 04/20] imports for offline signing --- .../src/commands/commands.rs | 10 ++++++---- demos/rust-cosmos-broadcaster-client/src/main.rs | 14 +++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 6625b31187..110e57115b 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -9,14 +9,16 @@ use cosmrs::tx::Msg; use cosmrs::{tx, AccountId, Coin, Denom}; use bip39; -pub async fn offline_sign() -> Vec { +pub async fn offline_sign(mnemonic: &String, to: &String) -> Vec { - // TODO load most of this from config file, take address and mnemonic from function args, take address and mnemonic from function args. in V2 take chain-id and tx-type as well + // TODO load most of this from config file. in V2 take chain-id and tx-type as well let prefix = "n"; let denom: Denom = "unym".parse().unwrap(); - let signer_mnemonic: bip39::Mnemonic = "".parse().unwrap(); + let signer_mnemonic: bip39::Mnemonic = mnemonic.parse().unwrap(); + // let signer_mnemonic: bip39::Mnemonic = "".parse().unwrap(); let validator = "https://qwerty-validator.qa.nymte.ch"; - let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap(); + let to_address: AccountId = to.parse().unwrap(); + // let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap(); let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, signer_mnemonic); let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone(); diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 46e245ab5e..63a01b9d96 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -30,8 +30,12 @@ enum Commands { #[derive(Debug, Clone, Args)] struct OfflineSignTx { - /// some random info for testing - string: String, + // / some random info for testing + // string: String, + /// mnemonic + mnemonic: String, + /// recipient nym address + to: String } #[derive(Debug, Args)] @@ -46,11 +50,11 @@ async fn main() { let cli = Cli::parse(); match &cli.command { - Some(Commands::OfflineSignTx(string)) => { - let tx_bytes = commands::commands::offline_sign(); + Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { + let tx_bytes = commands::commands::offline_sign(mnemonic, to); // TODO parse future // println!("{}", parsed.iter().format(", ")); - println!("end {:?}", string); + println!("signed"); } Some(Commands::SendTx(sp_address)) => { todo!(); From 0b311e2c05808838929c953ee7212b5a28b969c3 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 21:33:36 +0000 Subject: [PATCH 05/20] comment removal --- demos/rust-cosmos-broadcaster-client/src/main.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 63a01b9d96..d0f9b3cb06 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -30,11 +30,9 @@ enum Commands { #[derive(Debug, Clone, Args)] struct OfflineSignTx { - // / some random info for testing - // string: String, - /// mnemonic + /// mnemonic of signing + sending account (you!) mnemonic: String, - /// recipient nym address + /// recipient nyx chain address to: String } From b03d8f57d3b0b5c30d419cfa8a75f1aa252397f6 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 21:57:03 +0000 Subject: [PATCH 06/20] parsed returned bytes --- demos/rust-cosmos-broadcaster-client/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index d0f9b3cb06..9f768bef21 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -9,7 +9,6 @@ use clap::{CommandFactory, Parser, Subcommand, Args}; // use cosmrs::tx::Msg; // use cosmrs::{tx, AccountId, Coin, Denom}; // use bip39; - mod commands; #[derive(Debug, Parser)] @@ -31,9 +30,9 @@ enum Commands { #[derive(Debug, Clone, Args)] struct OfflineSignTx { /// mnemonic of signing + sending account (you!) - mnemonic: String, + mnemonic: String, // TODO input validation.. look @ file loading first /// recipient nyx chain address - to: String + to: String // TODO switch to proper cosmos address type } #[derive(Debug, Args)] @@ -49,9 +48,10 @@ async fn main() { match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { - let tx_bytes = commands::commands::offline_sign(mnemonic, to); - // TODO parse future - // println!("{}", parsed.iter().format(", ")); + let tx_bytes = commands::commands::offline_sign(mnemonic, to).await; + + // TODO save as global var to pass to sendtx() + println!("{:?}", tx_bytes.iter().collect::>()); println!("signed"); } Some(Commands::SendTx(sp_address)) => { From a86ed7afb8d163e64e787f963660accf05365fa2 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 22:45:15 +0000 Subject: [PATCH 07/20] type changes --- .../rust-cosmos-broadcaster-client/README.md | 2 +- .../src/commands/commands.rs | 13 ++++------ .../src/main.rs | 24 +++++++++++++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/README.md b/demos/rust-cosmos-broadcaster-client/README.md index dff78945d5..8429ffe82a 100644 --- a/demos/rust-cosmos-broadcaster-client/README.md +++ b/demos/rust-cosmos-broadcaster-client/README.md @@ -1,3 +1,3 @@ cosmos broadcaster client code - sign txs offline and send thru the mixnet! -heavily pulling from the offline_signing.rs example file in the validator client code (s/o Jon for writing top examples) \ No newline at end of file +heavily pulling from the offline_signing.rs example file in the validator client code (s/o Jon for writing top examples) & the nym-cli tool (:hattip: mr vez) \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 110e57115b..78f1826b75 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -9,18 +9,15 @@ use cosmrs::tx::Msg; use cosmrs::{tx, AccountId, Coin, Denom}; use bip39; -pub async fn offline_sign(mnemonic: &String, to: &String) -> Vec { +pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> Vec { - // TODO load most of this from config file. in V2 take chain-id and tx-type as well + // TODO take coin amount from function args, + load most of network vars from config file. in V2 take chain-id and tx-type as well - for V1 see nym-cli and how it loads from get_network_details() in main.rsL88 let prefix = "n"; let denom: Denom = "unym".parse().unwrap(); - let signer_mnemonic: bip39::Mnemonic = mnemonic.parse().unwrap(); - // let signer_mnemonic: bip39::Mnemonic = "".parse().unwrap(); let validator = "https://qwerty-validator.qa.nymte.ch"; - let to_address: AccountId = to.parse().unwrap(); - // let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap(); - let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, signer_mnemonic); + + let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic); let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone(); // local 'client' ONLY signing messages @@ -43,7 +40,7 @@ pub async fn offline_sign(mnemonic: &String, to: &String) -> Vec { let send_msg = MsgSend { from_address: signer_address.clone(), - to_address: to_address.clone(), + to_address: to.clone(), amount, } .to_any() diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 9f768bef21..6d64d6119b 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -9,12 +9,26 @@ use clap::{CommandFactory, Parser, Subcommand, Args}; // use cosmrs::tx::Msg; // use cosmrs::{tx, AccountId, Coin, Denom}; // use bip39; +use nym_validator_client::nyxd::AccountId; mod commands; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] #[clap(about = "binary with which users can perform offline signing and transmission of signed tx to broadcaster via the mixnet ")] struct Cli { + // TODO make this import from file & remove from functions + // #[clap(long, global = true)] + // #[clap( + // help = "Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC." + // )] + // mnemonic: Option, + + #[clap(short, long, global = true)] + #[clap( + help = "Overrides configuration as a file of environment variables." + )] + config_env_file: Option, + #[clap(subcommand)] command: Option, } @@ -29,10 +43,10 @@ enum Commands { #[derive(Debug, Clone, Args)] struct OfflineSignTx { - /// mnemonic of signing + sending account (you!) - mnemonic: String, // TODO input validation.. look @ file loading first + /// mnemonic of signing + sending account (you!) - this will be removed and replaced with file + mnemonic: bip39::Mnemonic, /// recipient nyx chain address - to: String // TODO switch to proper cosmos address type + to: AccountId } #[derive(Debug, Args)] @@ -48,7 +62,7 @@ async fn main() { match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { - let tx_bytes = commands::commands::offline_sign(mnemonic, to).await; + let tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; // TODO save as global var to pass to sendtx() println!("{:?}", tx_bytes.iter().collect::>()); @@ -57,6 +71,6 @@ async fn main() { Some(Commands::SendTx(sp_address)) => { todo!(); } - None => {} + None => {println!("no command specified - nothing to do")} } } \ No newline at end of file From 37b0aa4d084e5b049f6529df14d1558d0537cd49 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 4 Jul 2023 15:15:00 +0200 Subject: [PATCH 08/20] benchmark commit before adding network defaults --- .../src/commands/commands.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 78f1826b75..be04e5c6a2 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -27,16 +27,16 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> Vec { // (only broadcasts + queries for sequence numbers) let broadcaster = HttpClient::new(validator).unwrap(); - // get signer information - let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); - let chain_id = broadcaster.get_chain_id().await.unwrap(); - let signer_data = SignerData::new_from_sequence_response(sequence_response, chain_id); + // get signer information + let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); + let chain_id = broadcaster.get_chain_id().await.unwrap(); + let signer_data = SignerData::new_from_sequence_response(sequence_response, chain_id); - // create (and sign) the send message - let amount = vec![Coin { - denom: denom.clone(), - amount: 12345u32.into(), - }]; + // create (and sign) the send message + let amount = vec![Coin { + denom: denom.clone(), + amount: 12345u32.into(), + }]; let send_msg = MsgSend { from_address: signer_address.clone(), From e1e11149b4cb179cf50e59d07b4c2e066292bd42 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 4 Jul 2023 15:40:40 +0200 Subject: [PATCH 09/20] push to share code --- .../rust-cosmos-broadcaster-client/Cargo.toml | 1 + .../src/commands/commands.rs | 46 +++++++++---------- .../src/main.rs | 20 +++----- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml index b1c4c341b2..1e87d83cad 100644 --- a/demos/rust-cosmos-broadcaster-client/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] clap = { version = "4.0", features = ["derive"] } +nym-cli-commands = { path = "../../common/commands" } nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] } nym-network-defaults = { path = "../../common/network-defaults" } async-trait = { workspace = true, optional = true } diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index be04e5c6a2..af33555eae 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -11,12 +11,11 @@ use bip39; pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> Vec { - // TODO take coin amount from function args, + load most of network vars from config file. in V2 take chain-id and tx-type as well - for V1 see nym-cli and how it loads from get_network_details() in main.rsL88 + // TODO take coin amount from function args, + load network vars from config file. let prefix = "n"; let denom: Denom = "unym".parse().unwrap(); let validator = "https://qwerty-validator.qa.nymte.ch"; - let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic); let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone(); @@ -38,32 +37,31 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> Vec { amount: 12345u32.into(), }]; - let send_msg = MsgSend { - from_address: signer_address.clone(), - to_address: to.clone(), - amount, - } - .to_any() - .unwrap(); + let send_msg = MsgSend { + from_address: signer_address.clone(), + to_address: to.clone(), + amount, + } + .to_any() + .unwrap(); - let memo = "example memo"; - let fee = tx::Fee::from_amount_and_gas( - Coin { - denom, - amount: 2500u32.into(), - }, - 100000, - ); + let memo = "example memo"; + let fee = tx::Fee::from_amount_and_gas( + Coin { + denom, + amount: 2500u32.into(), + }, + 100000, + ); - let tx_raw = tx_signer - .sign_direct(&signer_address, vec![send_msg], fee, memo, signer_data) - .unwrap(); + let tx_raw = tx_signer + .sign_direct(&signer_address, vec![send_msg], fee, memo, signer_data) + .unwrap(); - // TODO return this from function - let tx_bytes = tx_raw.to_bytes().unwrap(); - - tx_bytes + // TODO return this from function + let tx_bytes = tx_raw.to_bytes().unwrap(); + tx_bytes } diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 6d64d6119b..551f09c7c4 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,22 +1,13 @@ use clap::{CommandFactory, Parser, Subcommand, Args}; -// use cosmrs::bip32::secp256k1::elliptic_curve::generic_array::sequence; -// use nym_validator_client::nyxd::CosmWasmClient; -// use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; -// use nym_validator_client::signing::tx_signer::TxSigner; -// use nym_validator_client::signing::SignerData; -// use cosmrs::bank::MsgSend; -// use cosmrs::rpc::{self, HttpClient}; -// use cosmrs::tx::Msg; -// use cosmrs::{tx, AccountId, Coin, Denom}; -// use bip39; use nym_validator_client::nyxd::AccountId; +// use nym_cli_commands::context::{get_network_details, ClientArgs}; mod commands; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] #[clap(about = "binary with which users can perform offline signing and transmission of signed tx to broadcaster via the mixnet ")] struct Cli { - // TODO make this import from file & remove from functions + // TODO make this import from file & remove from cli args // #[clap(long, global = true)] // #[clap( // help = "Provide the mnemonic for your account. You can also provide this is an env var called MNEMONIC." @@ -57,14 +48,15 @@ struct SendTx { #[tokio::main] async fn main() { + + let tx_bytes: Vec; let cli = Cli::parse(); match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { - let tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; + tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; - // TODO save as global var to pass to sendtx() println!("{:?}", tx_bytes.iter().collect::>()); println!("signed"); } @@ -73,4 +65,6 @@ async fn main() { } None => {println!("no command specified - nothing to do")} } + + println!(" ~(0.o)~ ") } \ No newline at end of file From 8a0330b4932ccbc9c042c64fdaef915ce4cb87b8 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 5 Jul 2023 09:28:21 +0200 Subject: [PATCH 10/20] push to share --- demos/rust-cosmos-broadcaster-client/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 551f09c7c4..c3d7e07a47 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -34,7 +34,7 @@ enum Commands { #[derive(Debug, Clone, Args)] struct OfflineSignTx { - /// mnemonic of signing + sending account (you!) - this will be removed and replaced with file + /// mnemonic of signing + sending account (you!) - TODO this will be removed and replaced with file mnemonic: bip39::Mnemonic, /// recipient nyx chain address to: AccountId @@ -56,9 +56,9 @@ async fn main() { match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; - - println!("{:?}", tx_bytes.iter().collect::>()); + println!("{:?}", &tx_bytes.iter().collect::>()); println!("signed"); + // TODO write to disk for use in next function? } Some(Commands::SendTx(sp_address)) => { todo!(); From 71f11ffefe74bbe44b42fbbe36d9f890967867d3 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 5 Jul 2023 14:51:53 +0200 Subject: [PATCH 11/20] trying to debug 'client in use' error --- .../rust-cosmos-broadcaster-client/Cargo.toml | 3 ++ .../src/commands/commands.rs | 43 ++++++++++++++-- .../src/main.rs | 51 ++++++++++++------- 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml index 1e87d83cad..21ae89a1b6 100644 --- a/demos/rust-cosmos-broadcaster-client/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -8,6 +8,8 @@ edition = "2021" [dependencies] clap = { version = "4.0", features = ["derive"] } +nym-bin-common = { path = "../../common/bin-common"} +nym-sdk = { path = "../../sdk/rust/nym-sdk" } nym-cli-commands = { path = "../../common/commands" } nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] } nym-network-defaults = { path = "../../common/network-defaults" } @@ -16,4 +18,5 @@ bip39 = { workspace = true, features = ["rand"] } cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"] } tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] } ts-rs = "6.1.2" +bs58 = "0.5.0" diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index af33555eae..477087dd47 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -8,8 +8,10 @@ use cosmrs::rpc::{self, HttpClient}; use cosmrs::tx::Msg; use cosmrs::{tx, AccountId, Coin, Denom}; use bip39; +use bs58; +use nym_sdk::mixnet; -pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> Vec { +pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { // TODO take coin amount from function args, + load network vars from config file. let prefix = "n"; @@ -58,11 +60,44 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> Vec { .sign_direct(&signer_address, vec![send_msg], fee, memo, signer_data) .unwrap(); - // TODO return this from function let tx_bytes = tx_raw.to_bytes().unwrap(); - - tx_bytes + let base58_tx_bytes = bs58::encode(tx_bytes).into_string(); + base58_tx_bytes } +pub async fn send_tx(base58_tx: String) -> Option> /*String*/ { + // 1. decode base58 -> vec + println!("this is where we decode the base58 string"); + // 2. get nym client address + let client = mixnet::MixnetClientBuilder::new_ephemeral() + .build() + .await + .unwrap(); + + let mut client = client.connect_to_mixnet().await.unwrap(); + + let our_address = client.nym_address(); + println!("Our client nym address is: {our_address}"); + + // client.send_str(*our_address, "hello there").await; + + // 3. send message w sdk to broadcaster who will do: + /* + // broadcast the tx + let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) + .await + .unwrap(); + */ + // client.send_str(sp_address, signedtx); + // println!("Waiting for message"); + let res = client.wait_for_messages().await; + + // disconnect client + // return the res to return to main thread + client.disconnect().await; + // String::from("your tx hash") + res + +} diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index c3d7e07a47..4391efb9dd 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,11 +1,13 @@ use clap::{CommandFactory, Parser, Subcommand, Args}; use nym_validator_client::nyxd::AccountId; // use nym_cli_commands::context::{get_network_details, ClientArgs}; +// use nym_crypto::asymmetric::identity; mod commands; +use nym_bin_common::logging::setup_logging; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] -#[clap(about = "binary with which users can perform offline signing and transmission of signed tx to broadcaster via the mixnet ")] +#[clap(about = "demo binary with which users can perform offline signing and transmission of signed tx to broadcaster via the mixnet ")] struct Cli { // TODO make this import from file & remove from cli args // #[clap(long, global = true)] @@ -14,11 +16,12 @@ struct Cli { // )] // mnemonic: Option, - #[clap(short, long, global = true)] - #[clap( - help = "Overrides configuration as a file of environment variables." - )] - config_env_file: Option, + // TODO add for diff network + // #[clap(short, long, global = true)] + // #[clap( + // help = "Overrides configuration as a file of environment variables." + // )] + // config_env_file: Option, #[clap(subcommand)] command: Option, @@ -42,29 +45,41 @@ struct OfflineSignTx { #[derive(Debug, Args)] struct SendTx { - /// the address of the nym service to send yr signed tx - sp_address: String // TODO replace with mixnet address type + /// the base58 encoded signed payload created in OfflineSign() + base58_payload: String } #[tokio::main] async fn main() { - - let tx_bytes: Vec; - + setup_logging(); let cli = Cli::parse(); + let sp_address = "4roCqqdh1mG76gYT2das1wNBER3e5AzxC5dsA4zoWoLh.2iRzCRhzVMod7Ar5MnGt3X3zJGR7c4NxvK8cXCnxMYe3@2xU4CBE6QiiYt6EyBXSALwxkNvM7gqJfjHXaMkjiFmYW"; match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { - tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; - println!("{:?}", &tx_bytes.iter().collect::>()); - println!("signed"); - // TODO write to disk for use in next function? + let base58_tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; + + println!("signed tx payload: \n\n{}\n\n", &base58_tx_bytes); + println!("do you wish to send the signed tx? y/n"); + + let mut input = String::new(); + let stdin = std::io::stdin(); + let n = stdin.read_line(&mut input).unwrap(); + + if input.chars().next().unwrap() == 'y' { // TODO add proper parsing for getting y/n + println!("\nsending tx thru the mixnet to broadcaster service"); + let tx_hash = commands::commands::send_tx(sp_address.to_string()).await; + println!("the response from the broadcaster: {:#?}", tx_hash); + } else if input.chars().next().unwrap() == 'n' { + println!("\nok, you can send the signed tx at a later date by passing the base58 string above as the argument for send-tx") + } else { //TODO make a loop & return to the question if input is not y/n + println!("\nunrecognised user input"); + } } - Some(Commands::SendTx(sp_address)) => { + Some(Commands::SendTx(SendTx { base58_payload } )) => { todo!(); } None => {println!("no command specified - nothing to do")} } - - println!(" ~(0.o)~ ") + println!(" end ~(0.o)~ ") } \ No newline at end of file From d64de95f521329e8c8829fd219600cf14359db6a Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 5 Jul 2023 14:57:00 +0200 Subject: [PATCH 12/20] sendTx(): fixed incorrect function arg --- .../src/commands/commands.rs | 4 +--- demos/rust-cosmos-broadcaster-client/src/main.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 477087dd47..18348a1e0f 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -66,7 +66,7 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { } -pub async fn send_tx(base58_tx: String) -> Option> /*String*/ { +pub async fn send_tx(base58_tx: String, sp_address: String) -> Option> /*String*/ { // 1. decode base58 -> vec println!("this is where we decode the base58 string"); @@ -80,8 +80,6 @@ pub async fn send_tx(base58_tx: String) -> Option { + Some(Commands::SendTx(SendTx { base58_payload, sp_address} )) => { todo!(); } None => {println!("no command specified - nothing to do")} From 18de02a2294a88243debbc984125975aedaab7a3 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 5 Jul 2023 16:43:27 +0200 Subject: [PATCH 13/20] first pass done of client --- .../rust-cosmos-broadcaster-client/Cargo.toml | 2 ++ .../src/commands/commands.rs | 24 +++++++------- .../src/main.rs | 33 +++++++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml index 21ae89a1b6..8a9c884013 100644 --- a/demos/rust-cosmos-broadcaster-client/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -9,7 +9,9 @@ edition = "2021" [dependencies] clap = { version = "4.0", features = ["derive"] } nym-bin-common = { path = "../../common/bin-common"} +nym-sphinx-addressing = { path = "../../common/nymsphinx/addressing" } nym-sdk = { path = "../../sdk/rust/nym-sdk" } +nym-crypto = { path = "../../common/crypto" } nym-cli-commands = { path = "../../common/commands" } nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] } nym-network-defaults = { path = "../../common/network-defaults" } diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 18348a1e0f..d12f8f6ebf 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -1,4 +1,5 @@ use cosmrs::bip32::secp256k1::elliptic_curve::generic_array::sequence; +use nym_sphinx_addressing::clients::Recipient; use nym_validator_client::nyxd::CosmWasmClient; use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; use nym_validator_client::signing::tx_signer::TxSigner; @@ -10,6 +11,7 @@ use cosmrs::{tx, AccountId, Coin, Denom}; use bip39; use bs58; use nym_sdk::mixnet; +// use nymsphinx::addressing::Recipient; pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { @@ -66,36 +68,34 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { } -pub async fn send_tx(base58_tx: String, sp_address: String) -> Option> /*String*/ { - // 1. decode base58 -> vec - println!("this is where we decode the base58 string"); - - // 2. get nym client address - let client = mixnet::MixnetClientBuilder::new_ephemeral() +pub async fn send_tx(base58_tx: String, sp_address: Recipient) -> Option> /*String*/ { + // TODO move to its own function and pass created client as arg + let config_dir = std::path::PathBuf::from("/tmp/mixnet-client"); + let storage_paths = mixnet::StoragePaths::new_from_dir(&config_dir).unwrap(); + let client = mixnet::MixnetClientBuilder::new_with_default_storage(storage_paths) + .await + .unwrap() .build() .await .unwrap(); - let mut client = client.connect_to_mixnet().await.unwrap(); - let our_address = client.nym_address(); println!("Our client nym address is: {our_address}"); - // 3. send message w sdk to broadcaster who will do: + // send message w sdk to broadcaster who will do: /* // broadcast the tx let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) .await .unwrap(); */ - // client.send_str(sp_address, signedtx); - // println!("Waiting for message"); + client.send_str(sp_address, &base58_tx).await; // send as base58 encoded and it can be decoded by the SP + println!("\nWaiting for reply\n"); let res = client.wait_for_messages().await; // disconnect client // return the res to return to main thread client.disconnect().await; - // String::from("your tx hash") res } diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index e764f8218f..4d0f9d2eff 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,9 +1,16 @@ +use std::str::FromStr; + use clap::{CommandFactory, Parser, Subcommand, Args}; +use cosmrs::bip32::PublicKey; +use nym_sdk::mixnet::Recipient; use nym_validator_client::nyxd::AccountId; // use nym_cli_commands::context::{get_network_details, ClientArgs}; -// use nym_crypto::asymmetric::identity; +use nym_crypto::asymmetric::identity; mod commands; use nym_bin_common::logging::setup_logging; +use nym_sphinx_addressing; + +// use common::nymsphinx::addressing; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] @@ -16,13 +23,8 @@ struct Cli { // )] // mnemonic: Option, - // TODO add for diff network - // #[clap(short, long, global = true)] - // #[clap( - // help = "Overrides configuration as a file of environment variables." - // )] - // config_env_file: Option, - + // TODO add SP address + #[clap(subcommand)] command: Option, } @@ -48,21 +50,23 @@ struct SendTx { /// the base58 encoded signed payload created in OfflineSign() base58_payload: String, /// the nym address of the broadcaster service provider - sp_address: String + sp_address: Recipient } #[tokio::main] async fn main() { setup_logging(); let cli = Cli::parse(); - let sp_address = "4roCqqdh1mG76gYT2das1wNBER3e5AzxC5dsA4zoWoLh.2iRzCRhzVMod7Ar5MnGt3X3zJGR7c4NxvK8cXCnxMYe3@2xU4CBE6QiiYt6EyBXSALwxkNvM7gqJfjHXaMkjiFmYW"; + // TODO take from args + let sp_address = Recipient::try_from_base58_string("6e5KeP3Ks6iA3832K2MvCvQJb9zF3HMHwY8XjLhwAGGt.ZCH8YTky6GkApmra3EGbfgQk2VwdPaRH8R1wUfAnv3Q@BNjYZPxzcJwczXHHgBxCAyVJKxN6LPteDRrKapxWmexv").unwrap(); + match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, to } )) => { let base58_tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; - println!("signed tx payload: \n\n{}\n\n", &base58_tx_bytes); - println!("do you wish to send the signed tx? y/n"); + println!("base58 encoded signed tx payload: \n\n{}\n\n", &base58_tx_bytes); + println!("do you wish to send the tx? y/n"); let mut input = String::new(); let stdin = std::io::stdin(); @@ -70,7 +74,7 @@ async fn main() { if input.chars().next().unwrap() == 'y' { // TODO add proper parsing for getting y/n println!("\nsending tx thru the mixnet to broadcaster service"); - let tx_hash = commands::commands::send_tx(base58_tx_bytes, sp_address.to_string()).await; + let tx_hash = commands::commands::send_tx(base58_tx_bytes, sp_address).await; println!("the response from the broadcaster: {:#?}", tx_hash); } else if input.chars().next().unwrap() == 'n' { println!("\nok, you can send the signed tx at a later date by passing the base58 string above as the argument for send-tx") @@ -79,7 +83,8 @@ async fn main() { } } Some(Commands::SendTx(SendTx { base58_payload, sp_address} )) => { - todo!(); + let tx_hash = commands::commands::send_tx(base58_payload.clone(), sp_address.clone()).await; + println!("the response from the broadcaster: {:#?}", tx_hash); } None => {println!("no command specified - nothing to do")} } From fbc106f8a58a4bf16fe0bc864a5b2f119291cb30 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 5 Jul 2023 18:34:01 +0200 Subject: [PATCH 14/20] removed unused imports --- .../src/commands/commands.rs | 8 +++++--- demos/rust-cosmos-broadcaster-client/src/main.rs | 12 ++---------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index d12f8f6ebf..a2e77e8193 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -1,17 +1,15 @@ -use cosmrs::bip32::secp256k1::elliptic_curve::generic_array::sequence; use nym_sphinx_addressing::clients::Recipient; use nym_validator_client::nyxd::CosmWasmClient; use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; use nym_validator_client::signing::tx_signer::TxSigner; use nym_validator_client::signing::SignerData; use cosmrs::bank::MsgSend; -use cosmrs::rpc::{self, HttpClient}; +use cosmrs::rpc::{HttpClient}; use cosmrs::tx::Msg; use cosmrs::{tx, AccountId, Coin, Denom}; use bip39; use bs58; use nym_sdk::mixnet; -// use nymsphinx::addressing::Recipient; pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { @@ -84,10 +82,14 @@ pub async fn send_tx(base58_tx: String, sp_address: Recipient) -> Option + // broadcast the tx let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) .await .unwrap(); + + // send res back via SURBs */ client.send_str(sp_address, &base58_tx).await; // send as base58 encoded and it can be decoded by the SP println!("\nWaiting for reply\n"); diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 4d0f9d2eff..83c7b1f87c 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,16 +1,8 @@ -use std::str::FromStr; - -use clap::{CommandFactory, Parser, Subcommand, Args}; -use cosmrs::bip32::PublicKey; +use clap::{ Parser, Subcommand, Args}; use nym_sdk::mixnet::Recipient; use nym_validator_client::nyxd::AccountId; -// use nym_cli_commands::context::{get_network_details, ClientArgs}; -use nym_crypto::asymmetric::identity; mod commands; use nym_bin_common::logging::setup_logging; -use nym_sphinx_addressing; - -// use common::nymsphinx::addressing; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] @@ -24,7 +16,7 @@ struct Cli { // mnemonic: Option, // TODO add SP address - + #[clap(subcommand)] command: Option, } From abbadcfa81e3c6254a0a285380d0b7e6ef204a8d Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 6 Jul 2023 09:56:37 +0200 Subject: [PATCH 15/20] working on proper client init and passing --- .../src/commands/commands.rs | 23 +++++++++---------- .../src/main.rs | 7 ++++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index a2e77e8193..7f97745178 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -27,10 +27,16 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { // possibly remote client that doesn't do ANY signing // (only broadcasts + queries for sequence numbers) let broadcaster = HttpClient::new(validator).unwrap(); - + +/////////////// to go on server side: need client from main passed as arg to send w sdk!! + // get sequence information and chain ID from the service + // add sdk, send req for sequence // get signer information let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); let chain_id = broadcaster.get_chain_id().await.unwrap(); +/////////////// + + // use the response to create SignerData instance let signer_data = SignerData::new_from_sequence_response(sequence_response, chain_id); // create (and sign) the send message @@ -66,17 +72,10 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { } -pub async fn send_tx(base58_tx: String, sp_address: Recipient) -> Option> /*String*/ { - // TODO move to its own function and pass created client as arg - let config_dir = std::path::PathBuf::from("/tmp/mixnet-client"); - let storage_paths = mixnet::StoragePaths::new_from_dir(&config_dir).unwrap(); - let client = mixnet::MixnetClientBuilder::new_with_default_storage(storage_paths) - .await - .unwrap() - .build() - .await - .unwrap(); - let mut client = client.connect_to_mixnet().await.unwrap(); +pub async fn send_tx(base58_tx: String, sp_address: Recipient) -> Option> { + + // TODO pass created client as arg frm main instead + let mut client = mixnet::MixnetClient::connect_new().await.unwrap(); let our_address = client.nym_address(); println!("Our client nym address is: {our_address}"); diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 83c7b1f87c..f2a6f5d40f 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,8 +1,9 @@ use clap::{ Parser, Subcommand, Args}; -use nym_sdk::mixnet::Recipient; +use nym_sdk::mixnet::{Recipient, MixnetClient}; use nym_validator_client::nyxd::AccountId; mod commands; use nym_bin_common::logging::setup_logging; +// use nym_sdk::mixnet; #[derive(Debug, Parser)] #[clap(name = "nym cosmos tx signer ")] @@ -35,6 +36,8 @@ struct OfflineSignTx { mnemonic: bip39::Mnemonic, /// recipient nyx chain address to: AccountId + // / nym client connection + // nym_client: MixnetClient } #[derive(Debug, Args)] @@ -49,7 +52,7 @@ struct SendTx { async fn main() { setup_logging(); let cli = Cli::parse(); - + // TODO look @ arg env setup from NR main.rs // TODO take from args let sp_address = Recipient::try_from_base58_string("6e5KeP3Ks6iA3832K2MvCvQJb9zF3HMHwY8XjLhwAGGt.ZCH8YTky6GkApmra3EGbfgQk2VwdPaRH8R1wUfAnv3Q@BNjYZPxzcJwczXHHgBxCAyVJKxN6LPteDRrKapxWmexv").unwrap(); From 33bc7c0c7c8c7b6b49dac909fd4cb4c7b7844b10 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 6 Jul 2023 16:28:01 +0200 Subject: [PATCH 16/20] setting up sdk links --- .../src/commands/commands.rs | 78 ++++++++++------ .../src/main.rs | 90 +++++++++++-------- .../rust-cosmos-broadcaster-server/Cargo.toml | 24 +++++ .../src/commands/commands.rs | 21 +++++ .../src/commands/mod.rs | 1 + .../src/main.rs | 62 +++++++++++++ 6 files changed, 212 insertions(+), 64 deletions(-) create mode 100644 demos/rust-cosmos-broadcaster-server/Cargo.toml create mode 100644 demos/rust-cosmos-broadcaster-server/src/commands/commands.rs create mode 100644 demos/rust-cosmos-broadcaster-server/src/commands/mod.rs create mode 100644 demos/rust-cosmos-broadcaster-server/src/main.rs diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 7f97745178..9f70ae23aa 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -1,17 +1,33 @@ +use nym_cli_commands::validator::mixnet::Mixnet; +use nym_crypto::generic_array::sequence; use nym_sphinx_addressing::clients::Recipient; use nym_validator_client::nyxd::CosmWasmClient; +use nym_validator_client::nyxd::cosmwasm_client::types::SequenceResponse; use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; use nym_validator_client::signing::tx_signer::TxSigner; use nym_validator_client::signing::SignerData; use cosmrs::bank::MsgSend; -use cosmrs::rpc::{HttpClient}; +use cosmrs::rpc::{HttpClient, Id}; use cosmrs::tx::Msg; use cosmrs::{tx, AccountId, Coin, Denom}; use bip39; use bs58; -use nym_sdk::mixnet; +use nym_sdk::mixnet::{self, MixnetClient}; +use serde::{Deserialize, Serialize}; +// use serde_json::Result; -pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { +#[derive(Deserialize, Serialize)] +struct SequenceRequestData<'a> { + validator: &'a str, + signer_address: AccountId +} + +struct SequenceResponseData { + sequence_response: SequenceResponse, + chain_id: Id +} + +pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut MixnetClient , sp_address: Recipient) -> String { // TODO take coin amount from function args, + load network vars from config file. let prefix = "n"; @@ -24,18 +40,32 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { // local 'client' ONLY signing messages let tx_signer = TxSigner::new(signer); +/////////////// to go on server side // possibly remote client that doesn't do ANY signing // (only broadcasts + queries for sequence numbers) - let broadcaster = HttpClient::new(validator).unwrap(); - -/////////////// to go on server side: need client from main passed as arg to send w sdk!! - // get sequence information and chain ID from the service - // add sdk, send req for sequence - // get signer information - let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); - let chain_id = broadcaster.get_chain_id().await.unwrap(); -/////////////// + // let broadcaster = HttpClient::new(validator).unwrap(); + // // get sequence information and chain ID from the service + // // add sdk, send req for sequence + // // get signer information +// let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); + // let chain_id = broadcaster.get_chain_id().await.unwrap(); +/////////////// + let message = SequenceRequestData{ + validator, + signer_address + }; + // send req to client + client.send_str(sp_address, &serde_json::to_string(&message).unwrap()).await; + let res = client.wait_for_messages().await; + for i in res.unwrap().iter() { + println!("{:#?}", i); + } + // parse json of res to get signer_data and chain_id, store in SeqResData struct + + todo!() + +/* // use the response to create SignerData instance let signer_data = SignerData::new_from_sequence_response(sequence_response, chain_id); @@ -69,16 +99,10 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId) -> String { let tx_bytes = tx_raw.to_bytes().unwrap(); let base58_tx_bytes = bs58::encode(tx_bytes).into_string(); base58_tx_bytes - +*/ } -pub async fn send_tx(base58_tx: String, sp_address: Recipient) -> Option> { - - // TODO pass created client as arg frm main instead - let mut client = mixnet::MixnetClient::connect_new().await.unwrap(); - let our_address = client.nym_address(); - println!("Our client nym address is: {our_address}"); - +pub async fn send_tx(base58_tx: String, sp_address: Recipient, client: &MixnetClient) -> Option> { // send message w sdk to broadcaster who will do: /* // decode the base58 tx to vec @@ -90,13 +114,9 @@ pub async fn send_tx(base58_tx: String, sp_address: Recipient) -> Option { - let base58_tx_bytes = commands::commands::offline_sign(mnemonic.clone(), to.clone()).await; + // TODO look @ arg env setup from NR main.rs + // TODO take from args + let sp_address = Recipient::try_from_base58_string("2f7rmjCSKt6YxNBVfKSzQmvbgr4wZRprP8wMgBCyD4Xi.3rv7jSLYZXjFjDiVfiS24UVmMHmH6uZnGbxuDxjMELPu@CfWcDJq8QBz6cVAPCYSaLbaJEhVTmHEmyYgQ6C5GdDW9").unwrap(); - println!("base58 encoded signed tx payload: \n\n{}\n\n", &base58_tx_bytes); - println!("do you wish to send the tx? y/n"); + // let mut client = MixnetClient::connect_new().await.unwrap(); // this was always seeing an existing connection... + // Specify some config options + let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-client"); + let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap(); + + // Create the client with a storage backend, and enable it by giving it some paths. If keys + // exists at these paths, they will be loaded, otherwise they will be generated. + let client = MixnetClientBuilder::new_with_default_storage(storage_paths) + .await + .unwrap() + .build() + .await + .unwrap(); + + // Now we connect to the mixnet, using keys now stored in the paths provided. + let mut client = client.connect_to_mixnet().await.unwrap(); + + // Be able to get our client address + let our_address = client.nym_address(); + println!("Our client nym address is: {our_address}"); + + match &cli.command { + Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, nyx_token_receipient} )) => { + let base58_tx_bytes = commands::commands::offline_sign(mnemonic.clone(), nyx_token_receipient.clone(), &mut client, sp_address.clone()).await; + + println!("base58 encoded signed tx payload: \n\n{}\n\n", &base58_tx_bytes); + println!("do you wish to send the tx? y/n"); let mut input = String::new(); let stdin = std::io::stdin(); let n = stdin.read_line(&mut input).unwrap(); if input.chars().next().unwrap() == 'y' { // TODO add proper parsing for getting y/n - println!("\nsending tx thru the mixnet to broadcaster service"); - let tx_hash = commands::commands::send_tx(base58_tx_bytes, sp_address).await; - println!("the response from the broadcaster: {:#?}", tx_hash); + println!("\nsending tx thru the mixnet to broadcaster service"); + let tx_hash = commands::commands::send_tx(base58_tx_bytes, sp_address, &client).await; + println!("the response from the broadcaster: {:#?}", tx_hash); } else if input.chars().next().unwrap() == 'n' { println!("\nok, you can send the signed tx at a later date by passing the base58 string above as the argument for send-tx") - } else { //TODO make a loop & return to the question if input is not y/n? + } else { //TODO make a loop & return to the question if input is not y/n? println!("\nunrecognised user input"); } } Some(Commands::SendTx(SendTx { base58_payload, sp_address} )) => { - let tx_hash = commands::commands::send_tx(base58_payload.clone(), sp_address.clone()).await; + let tx_hash = commands::commands::send_tx(base58_payload.clone(), sp_address.clone(), &client).await; println!("the response from the broadcaster: {:#?}", tx_hash); - } + } None => {println!("no command specified - nothing to do")} } - println!(" end ~(0.o)~ ") -} \ No newline at end of file + println!("\nend ~(0.o)~ ") +} diff --git a/demos/rust-cosmos-broadcaster-server/Cargo.toml b/demos/rust-cosmos-broadcaster-server/Cargo.toml new file mode 100644 index 0000000000..713d58ef67 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-server/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "rust-cosmos-broadcaster-server" +version = "0.1.0" +authors.workspace = true +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.0", features = ["derive"] } +nym-bin-common = { path = "../../common/bin-common"} +nym-sphinx-addressing = { path = "../../common/nymsphinx/addressing" } +nym-sdk = { path = "../../sdk/rust/nym-sdk" } +nym-crypto = { path = "../../common/crypto" } +nym-cli-commands = { path = "../../common/commands" } +nym-validator-client = { path = "../../common/client-libs/validator-client", features = ["nyxd-client"] } +nym-network-defaults = { path = "../../common/network-defaults" } +async-trait = { workspace = true, optional = true } +bip39 = { workspace = true, features = ["rand"] } +cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"] } +tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] } +ts-rs = "6.1.2" +bs58 = "0.5.0" + diff --git a/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs new file mode 100644 index 0000000000..8fa8899407 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs @@ -0,0 +1,21 @@ +/* +code for sequence and chain + // possibly remote client that doesn't do ANY signing + // (only broadcasts + queries for sequence numbers) + let broadcaster = HttpClient::new(validator).unwrap(); + + // get signer information + let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); + let chain_id = broadcaster.get_chain_id().await.unwrap(); + -> pass back chain_id and sequence_response to client side + +code for broadcast + // decode the base58 tx to vec + + // broadcast the tx + let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) + .await + .unwrap(); + + // send res back via SURBs + */ diff --git a/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs b/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs new file mode 100644 index 0000000000..6be336ee9f --- /dev/null +++ b/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs @@ -0,0 +1 @@ +pub mod commands; \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-server/src/main.rs b/demos/rust-cosmos-broadcaster-server/src/main.rs new file mode 100644 index 0000000000..c246db94cc --- /dev/null +++ b/demos/rust-cosmos-broadcaster-server/src/main.rs @@ -0,0 +1,62 @@ +use nym_sdk::mixnet::{Recipient, MixnetClient, StoragePaths, MixnetClientBuilder}; +use nym_validator_client::nyxd::AccountId; +use nym_bin_common::logging::setup_logging; +use std::path::PathBuf; +mod commands; + +#[tokio::main] +async fn main() { + setup_logging(); + + let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-server"); + let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap(); + let client = MixnetClientBuilder::new_with_default_storage(storage_paths) + .await + .unwrap() + .build() + .await + .unwrap(); + let mut client = client.connect_to_mixnet().await.unwrap(); + let our_address = client.nym_address(); + println!("Our client nym address is: {our_address}"); + + println!("Waiting for message"); + if let Some(received) = client.wait_for_messages().await { + // parse traffic based on... something ... and match {} to functions in commands + for r in received { + println!("Received: {}", String::from_utf8_lossy(&r.message)); + /* + deserialise json + check fn struct match + match{} and pass to function + */ + } + } + + // TODO V2 - multithreading! + client.disconnect().await; +} + + + +/* +code for sequence and chain + // possibly remote client that doesn't do ANY signing + // (only broadcasts + queries for sequence numbers) + let broadcaster = HttpClient::new(validator).unwrap(); + + // get signer information + let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); + let chain_id = broadcaster.get_chain_id().await.unwrap(); + -> pass back chain_id and sequence_response to client side + +code for broadcast + // decode the base58 tx to vec + + // broadcast the tx + let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) + .await + .unwrap(); + + // send res back via SURBs + */ From 80d38f795cc83aad4abc466f43b366e82340ccc2 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 6 Jul 2023 16:49:08 +0200 Subject: [PATCH 17/20] starting on serde for sp responses --- demos/rust-cosmos-broadcaster-client/Cargo.toml | 3 ++- demos/rust-cosmos-broadcaster-client/src/commands/commands.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/Cargo.toml b/demos/rust-cosmos-broadcaster-client/Cargo.toml index 8a9c884013..2a8074fcca 100644 --- a/demos/rust-cosmos-broadcaster-client/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-client/Cargo.toml @@ -21,4 +21,5 @@ cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegr tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] } ts-rs = "6.1.2" bs58 = "0.5.0" - +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 9f70ae23aa..4694e66c65 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -59,7 +59,7 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut client.send_str(sp_address, &serde_json::to_string(&message).unwrap()).await; let res = client.wait_for_messages().await; for i in res.unwrap().iter() { - println!("{:#?}", i); + println!("{:#?}", i.message); } // parse json of res to get signer_data and chain_id, store in SeqResData struct From 97693a496c3bf1382117186748c504f77e4b4b34 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 7 Jul 2023 11:23:56 +0200 Subject: [PATCH 18/20] working on sending client seq request to sp --- .../src/commands/commands.rs | 28 ++++++------------- .../src/main.rs | 20 ++++--------- .../rust-cosmos-broadcaster-server/Cargo.toml | 3 +- .../src/main.rs | 8 ++++-- 4 files changed, 23 insertions(+), 36 deletions(-) diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 4694e66c65..f27144aaf6 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -19,7 +19,8 @@ use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize)] struct SequenceRequestData<'a> { validator: &'a str, - signer_address: AccountId + signer_address: AccountId, + request_type: String } struct SequenceResponseData { @@ -53,7 +54,8 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut let message = SequenceRequestData{ validator, - signer_address + signer_address, + request_type: String::from("sequence_request") }; // send req to client client.send_str(sp_address, &serde_json::to_string(&message).unwrap()).await; @@ -102,21 +104,9 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut */ } -pub async fn send_tx(base58_tx: String, sp_address: Recipient, client: &MixnetClient) -> Option> { - // send message w sdk to broadcaster who will do: - /* - // decode the base58 tx to vec - - // broadcast the tx - let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) - .await - .unwrap(); - - // send res back via SURBs - */ - // client.send_str(sp_address, &base58_tx).await; // send as base58 encoded and it can be decoded by the SP - // println!("\nWaiting for reply\n"); - // let res = client.wait_for_messages().await; - // res - todo!() +pub async fn send_tx(base58_tx: String, sp_address: Recipient, client: &mut MixnetClient) -> Option> { + client.send_str(sp_address, &base58_tx).await; + println!("\nWaiting for reply\n"); + let res = client.wait_for_messages().await; + res } diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index dcf6a92a91..271b6a83b7 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -49,35 +49,27 @@ struct SendTx { #[tokio::main] async fn main() { - // setup_logging(); + setup_logging(); let cli = Cli::parse(); // TODO look @ arg env setup from NR main.rs // TODO take from args - let sp_address = Recipient::try_from_base58_string("2f7rmjCSKt6YxNBVfKSzQmvbgr4wZRprP8wMgBCyD4Xi.3rv7jSLYZXjFjDiVfiS24UVmMHmH6uZnGbxuDxjMELPu@CfWcDJq8QBz6cVAPCYSaLbaJEhVTmHEmyYgQ6C5GdDW9").unwrap(); - - // let mut client = MixnetClient::connect_new().await.unwrap(); // this was always seeing an existing connection... - // Specify some config options + let sp_address = Recipient::try_from_base58_string("6RkSh3QZCBQaSsMjZFSdRgRYkgKkKErQTtZtCyffsaSu.5xLdj5scMH116KazYDBUPRs16oE3BZhEAko8rjynTCJ6@E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM").unwrap(); + let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-client"); let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap(); - - // Create the client with a storage backend, and enable it by giving it some paths. If keys - // exists at these paths, they will be loaded, otherwise they will be generated. let client = MixnetClientBuilder::new_with_default_storage(storage_paths) .await .unwrap() .build() .await .unwrap(); - - // Now we connect to the mixnet, using keys now stored in the paths provided. let mut client = client.connect_to_mixnet().await.unwrap(); - - // Be able to get our client address let our_address = client.nym_address(); println!("Our client nym address is: {our_address}"); match &cli.command { Some(Commands::OfflineSignTx(OfflineSignTx { mnemonic, nyx_token_receipient} )) => { + println!("sending offline sign info"); let base58_tx_bytes = commands::commands::offline_sign(mnemonic.clone(), nyx_token_receipient.clone(), &mut client, sp_address.clone()).await; println!("base58 encoded signed tx payload: \n\n{}\n\n", &base58_tx_bytes); @@ -89,7 +81,7 @@ async fn main() { if input.chars().next().unwrap() == 'y' { // TODO add proper parsing for getting y/n println!("\nsending tx thru the mixnet to broadcaster service"); - let tx_hash = commands::commands::send_tx(base58_tx_bytes, sp_address, &client).await; + let tx_hash = commands::commands::send_tx(base58_tx_bytes, sp_address, &mut client).await; println!("the response from the broadcaster: {:#?}", tx_hash); } else if input.chars().next().unwrap() == 'n' { println!("\nok, you can send the signed tx at a later date by passing the base58 string above as the argument for send-tx") @@ -98,7 +90,7 @@ async fn main() { } } Some(Commands::SendTx(SendTx { base58_payload, sp_address} )) => { - let tx_hash = commands::commands::send_tx(base58_payload.clone(), sp_address.clone(), &client).await; + let tx_hash = commands::commands::send_tx(base58_payload.clone(), sp_address.clone(), &mut client).await; println!("the response from the broadcaster: {:#?}", tx_hash); } None => {println!("no command specified - nothing to do")} diff --git a/demos/rust-cosmos-broadcaster-server/Cargo.toml b/demos/rust-cosmos-broadcaster-server/Cargo.toml index 713d58ef67..4b7dfa0379 100644 --- a/demos/rust-cosmos-broadcaster-server/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-server/Cargo.toml @@ -21,4 +21,5 @@ cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegr tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] } ts-rs = "6.1.2" bs58 = "0.5.0" - +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } diff --git a/demos/rust-cosmos-broadcaster-server/src/main.rs b/demos/rust-cosmos-broadcaster-server/src/main.rs index c246db94cc..6e65e77312 100644 --- a/demos/rust-cosmos-broadcaster-server/src/main.rs +++ b/demos/rust-cosmos-broadcaster-server/src/main.rs @@ -3,6 +3,7 @@ use nym_validator_client::nyxd::AccountId; use nym_bin_common::logging::setup_logging; use std::path::PathBuf; mod commands; +use serde::{Deserialize, Serialize}; #[tokio::main] async fn main() { @@ -22,9 +23,12 @@ async fn main() { println!("Waiting for message"); if let Some(received) = client.wait_for_messages().await { - // parse traffic based on... something ... and match {} to functions in commands + for r in received { - println!("Received: {}", String::from_utf8_lossy(&r.message)); + let to_parse = String::from_utf8_lossy(&r.message); + println!("Received: {}", &to_parse); + let parsed = serde_json::from_str(&to_parse).unwrap(); + /* deserialise json check fn struct match From 7f37c95599358b7dce1dc83ae6d2ec696d2c92e6 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 7 Jul 2023 17:01:45 +0200 Subject: [PATCH 19/20] passing message types properly between client and sp --- demos/rust-cosmos-broadcaster-client/plan.txt | 13 ----- .../src/commands/commands.rs | 32 ++++++++----- .../rust-cosmos-broadcaster-server/Cargo.toml | 1 + .../src/main.rs | 48 +++++++++++++++++-- 4 files changed, 65 insertions(+), 29 deletions(-) delete mode 100644 demos/rust-cosmos-broadcaster-client/plan.txt diff --git a/demos/rust-cosmos-broadcaster-client/plan.txt b/demos/rust-cosmos-broadcaster-client/plan.txt deleted file mode 100644 index 3ff129e190..0000000000 --- a/demos/rust-cosmos-broadcaster-client/plan.txt +++ /dev/null @@ -1,13 +0,0 @@ -Plan: -* rewrite ts cosmos broadcaster SP in rust -* create simple rust binary for client cli use with 2 functions: - * use standard CLI method - cf. NymCLI - * getSequence() for offline signing - * submitTx() for sending tx thru mixnet to SP for broadcasting - -* rust server code - communicates with chain - * sdk - * nym validator client - broadcast client, gets sequence + submits tx -* rust client code - communicates with server via mixnet - * sdk - * nym validator client - offline signer diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index f27144aaf6..90d11e1c8b 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -2,7 +2,7 @@ use nym_cli_commands::validator::mixnet::Mixnet; use nym_crypto::generic_array::sequence; use nym_sphinx_addressing::clients::Recipient; use nym_validator_client::nyxd::CosmWasmClient; -use nym_validator_client::nyxd::cosmwasm_client::types::SequenceResponse; +// use nym_validator_client::nyxd::cosmwasm_client::types::SequenceResponse; use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; use nym_validator_client::signing::tx_signer::TxSigner; use nym_validator_client::signing::SignerData; @@ -17,15 +17,25 @@ use serde::{Deserialize, Serialize}; // use serde_json::Result; #[derive(Deserialize, Serialize)] -struct SequenceRequestData<'a> { - validator: &'a str, +struct SequenceRequest { + validator: String, signer_address: AccountId, - request_type: String + // request_type: String +} +#[derive(Deserialize, Serialize)] +struct SequenceResponse { + sequence_response: u8, + chain_id: Id } -struct SequenceResponseData { - sequence_response: SequenceResponse, - chain_id: Id +enum RequestTypes { + Sequence(SequenceRequest), + // Broadcast(BroadcastRequest) +} + +enum ResponseTypes { + Sequence(SequenceResponse), + // Broadcast(BroadcastResponse) } pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut MixnetClient , sp_address: Recipient) -> String { @@ -33,7 +43,7 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut // TODO take coin amount from function args, + load network vars from config file. let prefix = "n"; let denom: Denom = "unym".parse().unwrap(); - let validator = "https://qwerty-validator.qa.nymte.ch"; + let validator = String::from("https://qwerty-validator.qa.nymte.ch"); let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic); let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone(); @@ -52,10 +62,10 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut // let chain_id = broadcaster.get_chain_id().await.unwrap(); /////////////// - let message = SequenceRequestData{ + let message = SequenceRequest{ validator, signer_address, - request_type: String::from("sequence_request") + // request_type: String::from("sequence_request") }; // send req to client client.send_str(sp_address, &serde_json::to_string(&message).unwrap()).await; @@ -64,7 +74,7 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut println!("{:#?}", i.message); } // parse json of res to get signer_data and chain_id, store in SeqResData struct - + todo!() /* diff --git a/demos/rust-cosmos-broadcaster-server/Cargo.toml b/demos/rust-cosmos-broadcaster-server/Cargo.toml index 4b7dfa0379..1459abd08c 100644 --- a/demos/rust-cosmos-broadcaster-server/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-server/Cargo.toml @@ -10,6 +10,7 @@ edition = "2021" clap = { version = "4.0", features = ["derive"] } nym-bin-common = { path = "../../common/bin-common"} nym-sphinx-addressing = { path = "../../common/nymsphinx/addressing" } +nym-sphinx-anonymous-replies = { path = "../../common/nymsphinx/anonymous-replies" } nym-sdk = { path = "../../sdk/rust/nym-sdk" } nym-crypto = { path = "../../common/crypto" } nym-cli-commands = { path = "../../common/commands" } diff --git a/demos/rust-cosmos-broadcaster-server/src/main.rs b/demos/rust-cosmos-broadcaster-server/src/main.rs index 6e65e77312..b7e85d2e83 100644 --- a/demos/rust-cosmos-broadcaster-server/src/main.rs +++ b/demos/rust-cosmos-broadcaster-server/src/main.rs @@ -4,6 +4,31 @@ use nym_bin_common::logging::setup_logging; use std::path::PathBuf; mod commands; use serde::{Deserialize, Serialize}; +use cosmrs::rpc::{Id}; +use nym_sphinx_anonymous_replies::{self, requests::RepliableMessage}; + + +#[derive(Debug, Deserialize, Serialize)] +struct SequenceRequest { + validator: String, + signer_address: AccountId, + // request_type: String +} +#[derive(Deserialize, Serialize)] +struct SequenceResponse { + sequence_response: u8, + chain_id: Id +} +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +enum RequestTypes { + Sequence(SequenceRequest), + // Broadcast(BroadcastRequest) +} +enum ResponseTypes { + Sequence(SequenceResponse), + // Broadcast(BroadcastResponse) +} #[tokio::main] async fn main() { @@ -21,13 +46,26 @@ async fn main() { let our_address = client.nym_address(); println!("Our client nym address is: {our_address}"); - println!("Waiting for message"); + println!("\nWaiting for message"); if let Some(received) = client.wait_for_messages().await { - for r in received { - let to_parse = String::from_utf8_lossy(&r.message); - println!("Received: {}", &to_parse); - let parsed = serde_json::from_str(&to_parse).unwrap(); + for r in &received { + let s = String::from_utf8(r.message.clone()); + if s.is_ok() { + let p = s.unwrap(); + let request: RequestTypes = serde_json::from_str(&p).unwrap(); + println!("incoming request: {:#?}", &request); + match request { + RequestTypes::Sequence(SequenceRequest) => { + println!("matched!") + // TODO pass to commands::fn + }, + // RequestTypes::Broadcast(BroadcastRequest) // TODO + _ => { + println!(" (x_x) ") + } + } + } /* deserialise json From bc565c494b470ed963807ac170dfb84610bcbb57 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 10 Jul 2023 09:08:40 +0200 Subject: [PATCH 20/20] almost got surb reply.. --- .../src/commands/commands.rs | 36 +------ .../src/commands/commands/reqres.rs | 0 .../src/commands/mod.rs | 3 +- .../src/commands/reqres.rs | 40 +++++++ .../src/main.rs | 7 +- .../rust-cosmos-broadcaster-server/Cargo.toml | 1 + .../src/commands/commands.rs | 61 ++++++++--- .../src/commands/mod.rs | 3 +- .../src/commands/reqres.rs | 40 +++++++ .../src/main.rs | 102 +++++++----------- 10 files changed, 172 insertions(+), 121 deletions(-) create mode 100644 demos/rust-cosmos-broadcaster-client/src/commands/commands/reqres.rs create mode 100644 demos/rust-cosmos-broadcaster-client/src/commands/reqres.rs create mode 100644 demos/rust-cosmos-broadcaster-server/src/commands/reqres.rs diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs index 90d11e1c8b..3b6c871fc1 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/commands.rs @@ -2,7 +2,6 @@ use nym_cli_commands::validator::mixnet::Mixnet; use nym_crypto::generic_array::sequence; use nym_sphinx_addressing::clients::Recipient; use nym_validator_client::nyxd::CosmWasmClient; -// use nym_validator_client::nyxd::cosmwasm_client::types::SequenceResponse; use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; use nym_validator_client::signing::tx_signer::TxSigner; use nym_validator_client::signing::SignerData; @@ -14,29 +13,7 @@ use bip39; use bs58; use nym_sdk::mixnet::{self, MixnetClient}; use serde::{Deserialize, Serialize}; -// use serde_json::Result; - -#[derive(Deserialize, Serialize)] -struct SequenceRequest { - validator: String, - signer_address: AccountId, - // request_type: String -} -#[derive(Deserialize, Serialize)] -struct SequenceResponse { - sequence_response: u8, - chain_id: Id -} - -enum RequestTypes { - Sequence(SequenceRequest), - // Broadcast(BroadcastRequest) -} - -enum ResponseTypes { - Sequence(SequenceResponse), - // Broadcast(BroadcastResponse) -} +use crate::commands::reqres::SequenceRequest; pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut MixnetClient , sp_address: Recipient) -> String { @@ -51,17 +28,6 @@ pub async fn offline_sign(mnemonic: bip39::Mnemonic, to: AccountId, client: &mut // local 'client' ONLY signing messages let tx_signer = TxSigner::new(signer); -/////////////// to go on server side - // possibly remote client that doesn't do ANY signing - // (only broadcasts + queries for sequence numbers) - // let broadcaster = HttpClient::new(validator).unwrap(); - // // get sequence information and chain ID from the service - // // add sdk, send req for sequence - // // get signer information -// let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); - // let chain_id = broadcaster.get_chain_id().await.unwrap(); -/////////////// - let message = SequenceRequest{ validator, signer_address, diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/commands/reqres.rs b/demos/rust-cosmos-broadcaster-client/src/commands/commands/reqres.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs b/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs index 6be336ee9f..b4eb760edf 100644 --- a/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs +++ b/demos/rust-cosmos-broadcaster-client/src/commands/mod.rs @@ -1 +1,2 @@ -pub mod commands; \ No newline at end of file +pub mod reqres; +pub mod commands; diff --git a/demos/rust-cosmos-broadcaster-client/src/commands/reqres.rs b/demos/rust-cosmos-broadcaster-client/src/commands/reqres.rs new file mode 100644 index 0000000000..725ad57aa8 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-client/src/commands/reqres.rs @@ -0,0 +1,40 @@ +use cosmrs::rpc::{Id}; +use serde::{Deserialize, Serialize}; +use cosmrs::{AccountId}; + +#[derive(Deserialize, Serialize, Debug)] +pub struct SequenceRequest { + pub validator: String, + pub signer_address: AccountId, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct SequenceResponse { + pub sequence_response: u8, + pub chain_id: Id +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct BroadcastRequest { + pub base58_tx_bytes: String +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct BroadcastResponse{ + pub tx_hash: String +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum RequestTypes { + Sequence(SequenceRequest), + Broadcast(BroadcastRequest) +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ResponseTypes { + Sequence(SequenceResponse), + Broadcast(BroadcastResponse) +} + diff --git a/demos/rust-cosmos-broadcaster-client/src/main.rs b/demos/rust-cosmos-broadcaster-client/src/main.rs index 271b6a83b7..151f977ca3 100644 --- a/demos/rust-cosmos-broadcaster-client/src/main.rs +++ b/demos/rust-cosmos-broadcaster-client/src/main.rs @@ -1,7 +1,6 @@ use std::path::PathBuf; - use clap::{ Parser, Subcommand, Args}; -use nym_sdk::mixnet::{Recipient, MixnetClient, MixnetClientBuilder, StoragePaths}; +use nym_sdk::mixnet::{Recipient, MixnetClientBuilder, StoragePaths}; use nym_validator_client::nyxd::AccountId; use nym_bin_common::logging::setup_logging; mod commands; @@ -53,9 +52,9 @@ async fn main() { let cli = Cli::parse(); // TODO look @ arg env setup from NR main.rs // TODO take from args - let sp_address = Recipient::try_from_base58_string("6RkSh3QZCBQaSsMjZFSdRgRYkgKkKErQTtZtCyffsaSu.5xLdj5scMH116KazYDBUPRs16oE3BZhEAko8rjynTCJ6@E3mvZTHQCdBvhfr178Swx9g4QG3kkRUun7YnToLMcMbM").unwrap(); + let sp_address = Recipient::try_from_base58_string("58t3wcC14TYvhbq8ATpoQmf9jtJ44pYYU1oj9KKYokQu.BAR7nDgfJxSpatuXB97gqa1rvhfeTvHgVmPkJrvU8pz6@DfNMqQRy6pPkU8Z5rBsxRwzDUzAMXHPFwMhjF16ScZqn").unwrap(); - let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-client"); + let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-client-2"); let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap(); let client = MixnetClientBuilder::new_with_default_storage(storage_paths) .await diff --git a/demos/rust-cosmos-broadcaster-server/Cargo.toml b/demos/rust-cosmos-broadcaster-server/Cargo.toml index 1459abd08c..cc13efd57b 100644 --- a/demos/rust-cosmos-broadcaster-server/Cargo.toml +++ b/demos/rust-cosmos-broadcaster-server/Cargo.toml @@ -24,3 +24,4 @@ ts-rs = "6.1.2" bs58 = "0.5.0" serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } +cosmwasm-std = { workspace = true, optional = true } \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs b/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs index 8fa8899407..64bbf66d8f 100644 --- a/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs +++ b/demos/rust-cosmos-broadcaster-server/src/commands/commands.rs @@ -1,21 +1,54 @@ -/* -code for sequence and chain - // possibly remote client that doesn't do ANY signing - // (only broadcasts + queries for sequence numbers) - let broadcaster = HttpClient::new(validator).unwrap(); +// use nym_cli_commands::validator::mixnet::Mixnet; +// use nym_crypto::generic_array::sequence; +// use nym_sphinx_addressing::clients::Recipient; +use nym_validator_client::nyxd::CosmWasmClient; +// use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet; +// use nym_validator_client::signing::tx_signer::TxSigner; +// use nym_validator_client::signing::SignerData; +// use cosmrs::bank::MsgSend; +use cosmrs::rpc::{HttpClient, Id, Client}; +// use cosmrs::tx::Msg; +use cosmrs::{tx, AccountId, Coin, Denom}; +// use bip39; +use bs58; +use nym_sdk::mixnet::{self, MixnetClient}; +use serde::{Deserialize, Serialize}; +use crate::commands::reqres::{SequenceRequest, SequenceRequestResponse}; + +pub async fn get_sequence(validator: String, signer_address: AccountId) -> SequenceRequestResponse { + + /* + TODO create broadcaster in different fn and build on setup - pass to both fns as arg + */ + let broadcaster = HttpClient::new(validator.as_str()).unwrap(); // get signer information - let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); + // TODO look @ how you can return SequenceResponse type from cosmwasm + let sequence = broadcaster.get_sequence(&signer_address).await.unwrap(); let chain_id = broadcaster.get_chain_id().await.unwrap(); - -> pass back chain_id and sequence_response to client side + // todo!() + let res = SequenceRequestResponse { sequence: 9, chain_id: cosmrs::rpc::Id::Str(String::from("chain_id_placeholder")) }; + res +} + +pub async fn broadcast(base58_tx_bytes: String) -> String { + todo!(); + + /* + TODO create broadcaster in different fn and build on setup - pass to both fns as arg + */ -code for broadcast // decode the base58 tx to vec + // let tx_bytes = bs58::decode(base58_tx_bytes); - // broadcast the tx - let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) - .await - .unwrap(); + // // create instance of Transaction struct w tx_bytes - tx_to_broadcast - // send res back via SURBs - */ + // // broadcast the tx + // let res = Client::broadcast_tx_commit(&broadcaster, tx_to_broadcast) + // .await + // .unwrap(); + + // let placeholder = String::from("palceholder"); + // placeholder + +} \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs b/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs index 6be336ee9f..b4eb760edf 100644 --- a/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs +++ b/demos/rust-cosmos-broadcaster-server/src/commands/mod.rs @@ -1 +1,2 @@ -pub mod commands; \ No newline at end of file +pub mod reqres; +pub mod commands; diff --git a/demos/rust-cosmos-broadcaster-server/src/commands/reqres.rs b/demos/rust-cosmos-broadcaster-server/src/commands/reqres.rs new file mode 100644 index 0000000000..df67f405c8 --- /dev/null +++ b/demos/rust-cosmos-broadcaster-server/src/commands/reqres.rs @@ -0,0 +1,40 @@ +use cosmrs::rpc::{HttpClient, Id}; +use serde::{Deserialize, Serialize}; +use cosmrs::{tx, AccountId, Coin, Denom}; +use nym_validator_client::nyxd::cosmwasm_client::types::SequenceResponse; + +#[derive(Deserialize, Serialize, Debug)] +pub struct SequenceRequest { + pub validator: String, + pub signer_address: AccountId, +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct SequenceRequestResponse { + pub sequence: u8, // fix this - should be cosmwasmclient::SequenceResponse + pub chain_id: Id +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct BroadcastRequest { + pub base58_tx_bytes: String +} + +#[derive(Deserialize, Serialize, Debug)] +pub struct BroadcastResponse{ + pub tx_hash: String +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum RequestTypes { + Sequence(SequenceRequest), + Broadcast(BroadcastRequest) +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ResponseTypes { + Sequence(SequenceRequestResponse), + Broadcast(BroadcastResponse) +} \ No newline at end of file diff --git a/demos/rust-cosmos-broadcaster-server/src/main.rs b/demos/rust-cosmos-broadcaster-server/src/main.rs index b7e85d2e83..9297641af7 100644 --- a/demos/rust-cosmos-broadcaster-server/src/main.rs +++ b/demos/rust-cosmos-broadcaster-server/src/main.rs @@ -4,37 +4,16 @@ use nym_bin_common::logging::setup_logging; use std::path::PathBuf; mod commands; use serde::{Deserialize, Serialize}; -use cosmrs::rpc::{Id}; -use nym_sphinx_anonymous_replies::{self, requests::RepliableMessage}; - - -#[derive(Debug, Deserialize, Serialize)] -struct SequenceRequest { - validator: String, - signer_address: AccountId, - // request_type: String -} -#[derive(Deserialize, Serialize)] -struct SequenceResponse { - sequence_response: u8, - chain_id: Id -} -#[derive(Debug, Deserialize, Serialize)] -#[serde(untagged)] -enum RequestTypes { - Sequence(SequenceRequest), - // Broadcast(BroadcastRequest) -} -enum ResponseTypes { - Sequence(SequenceResponse), - // Broadcast(BroadcastResponse) -} +use cosmrs::{rpc::{Id}}; +use nym_sphinx_anonymous_replies::{self, requests::RepliableMessage}; +use crate::commands::reqres; +// pull in ::reply::{MixnetAddress, MixnetMessage} #[tokio::main] async fn main() { setup_logging(); - - let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-server"); + // TODO put client creation in own fn + let config_dir = PathBuf::from("/tmp/cosmos-broadcaster-mixnet-server-2"); let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap(); let client = MixnetClientBuilder::new_with_default_storage(storage_paths) .await @@ -44,61 +23,52 @@ async fn main() { .unwrap(); let mut client = client.connect_to_mixnet().await.unwrap(); let our_address = client.nym_address(); - println!("Our client nym address is: {our_address}"); + println!("\nOur client nym address is: {our_address}"); + /* + TODO + * make process just wait for another message instead of end after single match() + * add threads! + */ println!("\nWaiting for message"); if let Some(received) = client.wait_for_messages().await { - for r in &received { let s = String::from_utf8(r.message.clone()); if s.is_ok() { let p = s.unwrap(); - let request: RequestTypes = serde_json::from_str(&p).unwrap(); + let request: reqres::RequestTypes = serde_json::from_str(&p).unwrap(); println!("incoming request: {:#?}", &request); match request { - RequestTypes::Sequence(SequenceRequest) => { - println!("matched!") - // TODO pass to commands::fn - }, - // RequestTypes::Broadcast(BroadcastRequest) // TODO - _ => { - println!(" (x_x) ") - } + reqres::RequestTypes::Sequence(request) => { + println!("\nincoming sequence request details:\nvalidator: {},\nsigner address: {}\n", request.validator, request.signer_address); + let sequence: reqres::SequenceRequestResponse = commands::commands::get_sequence(request.validator, request.signer_address).await; + print!("debug print -------- {:#?}", sequence); + + // send back to sender via SURBS... + // TODO how to properly parse to AnonymousSenderTag? + // TODO make a rust sdk example of replying via SURBs + println!("debug print SENDER TAG --------- {:#?}", r.sender_tag); + + if Some(r.sender_tag).is_some() { + // TODO construct reply + let return_recipient = MixnetAddress::from(r.sender_tag); + // send back thru mixnet + client.send_str(return_recipient, &serde_json::to_string(&sequence).unwrap()).await; + } else { + // // TODO replace with actual error type to return + println!("no surbs cannot reply an0n") + } + }, + reqres::RequestTypes::Broadcast(BroadcastRequest) => { + todo!() + } } } - - /* - deserialise json - check fn struct match - match{} and pass to function - */ } } - // TODO V2 - multithreading! client.disconnect().await; } -/* -code for sequence and chain - // possibly remote client that doesn't do ANY signing - // (only broadcasts + queries for sequence numbers) - let broadcaster = HttpClient::new(validator).unwrap(); - - // get signer information - let sequence_response = broadcaster.get_sequence(&signer_address).await.unwrap(); - let chain_id = broadcaster.get_chain_id().await.unwrap(); - -> pass back chain_id and sequence_response to client side - -code for broadcast - // decode the base58 tx to vec - - // broadcast the tx - let res = rpc::Client::broadcast_tx_commit(&broadcaster, tx_bytes.into()) - .await - .unwrap(); - - // send res back via SURBs - */