From dfce9ced1df68fd79e2addff31c6567ab53bfdb3 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 3 Jul 2023 21:17:29 +0000 Subject: [PATCH] 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