Skip to content

Commit

Permalink
Merge pull request #3 from gotabit:add_broadcast_tx
Browse files Browse the repository at this point in the history
feat(grpc_client): Add broadcast transaction
  • Loading branch information
jacksoom authored Sep 25, 2023
2 parents 3d5e5b2 + 3ee233a commit 50cddfc
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 84 deletions.
1 change: 1 addition & 0 deletions grpc-client/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion grpc-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ bip32 = "0.5.1"
tonic = { version = "0.9.0", optional = true, default-features = false, features = ["codegen", "prost", "tls", "tls-roots"] }
cosmrs = "0.14.0"
prost-types = "0.11"
signature = "2.1.0"

[features]
default = ["grpc-transport"]
Expand All @@ -21,4 +22,4 @@ grpc-transport = ["grpc", "tonic/transport"]
cosmwasm = []

[dev-dependencies]
log = "0.4.20" # A lightweight logging facade for Rust
log = "0.4.20" # A lightweight logging facade for Rust
97 changes: 97 additions & 0 deletions grpc-client/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
use cosmrs::crypto::secp256k1::SigningKey;
use gotabit_sdk_proto::cosmos::auth::v1beta1::{BaseAccount, QueryAccountRequest};
use gotabit_sdk_proto::cosmos::base::v1beta1::Coin;
use gotabit_sdk_proto::cosmos::tx::signing::v1beta1::SignMode;
use gotabit_sdk_proto::cosmos::tx::v1beta1::mode_info::{self};
use gotabit_sdk_proto::cosmos::tx::v1beta1::{
AuthInfo, BroadcastMode, BroadcastTxRequest, Fee, SignDoc, SignerInfo, Tip, TxBody, TxRaw,
};
use gotabit_sdk_proto::cosmos::tx::v1beta1::{BroadcastTxResponse, ModeInfo};
use std::error::Error;
use tonic::transport::Channel;

use gotabit_sdk_proto::cosmos::{
Expand Down Expand Up @@ -31,6 +41,8 @@ use gotabit_sdk_proto::cosmwasm::wasm::v1::{

use crate::networks::NetworkInfo;

use gotabit_sdk_proto::traits::MessageExt;

pub struct Cosmos {
pub app: AppCli<Channel>,
pub auth: AuthCli<Channel>,
Expand Down Expand Up @@ -121,4 +133,89 @@ impl GrpcClient {
},
})
}

pub async fn broadcast_tx_sync<T>(
&mut self,
sign_key: SigningKey,
addr: String,
msg: T,
coin: Coin,
memo: String,
timeout_height: u64,
gas: u64,
tx_tip: Option<Tip>,
) -> Result<tonic::Response<BroadcastTxResponse>, Box<dyn Error>>
where
T: gotabit_sdk_proto::traits::MessageExt + gotabit_sdk_proto::traits::TypeUrl,
{
// get account seq
let base_account_resp = self
.clients
.cosmos
.auth
.account(QueryAccountRequest { address: addr })
.await?
.into_inner();
let base_acct: BaseAccount =
BaseAccount::from_any(&base_account_resp.account.unwrap()).unwrap();

// build a simple transfer transction and sign
let tx_body = TxBody {
messages: vec![msg.to_any().unwrap()],
memo,
timeout_height,
extension_options: Default::default(),
non_critical_extension_options: Default::default(),
};

// build a single sign
let signer_info = SignerInfo {
public_key: Some(sign_key.public_key().into()),
mode_info: Some(ModeInfo {
sum: Some(mode_info::Sum::Single(mode_info::Single {
mode: SignMode::Direct.into(),
})),
}),
sequence: base_acct.sequence,
};

let auth_info = AuthInfo {
signer_infos: vec![signer_info],
fee: Some(Fee {
amount: vec![coin],
gas_limit: gas,
payer: Default::default(),
granter: Default::default(),
}),
tip: tx_tip,
};

let sign_doc = SignDoc {
body_bytes: tx_body.to_bytes()?,
auth_info_bytes: auth_info.to_bytes()?,
chain_id: self.chain_id.to_string(),
account_number: base_acct.account_number,
};

let sign_doc_bytes = sign_doc.to_bytes()?;
let sign = sign_key.sign(&sign_doc_bytes)?;

let tx_raw = TxRaw {
body_bytes: sign_doc.body_bytes,
auth_info_bytes: auth_info.to_bytes().unwrap(),
signatures: vec![sign.to_vec()],
};

let resp = self
.clients
.cosmos
.tx
.broadcast_tx(BroadcastTxRequest {
tx_bytes: tx_raw.to_bytes().unwrap(),
mode: BroadcastMode::Sync.into(),
})
.await?;

Ok(resp)
}
}
97 changes: 14 additions & 83 deletions grpc-client/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,13 @@ use crate::{cli::GrpcClient, networks::TEST_NET};

use gotabit_sdk_proto::cosmos::bank::v1beta1::MsgSend;
use gotabit_sdk_proto::cosmos::base::v1beta1::Coin;
use gotabit_sdk_proto::cosmos::tx::v1beta1::{
mode_info, AuthInfo, BroadcastMode, BroadcastTxRequest, Fee, ModeInfo, SignDoc, SignerInfo,
TxBody, TxRaw,
};

use cosmrs::crypto::secp256k1;
use gotabit_sdk_proto::cosmos::tx::signing::v1beta1::SignMode;
use gotabit_sdk_proto::cosmos::bank::v1beta1::QueryBalanceRequest;
use gotabit_sdk_proto::cosmwasm::wasm::v1::QueryContractInfoRequest;
use gotabit_sdk_proto::{
cosmos::auth::v1beta1::BaseAccount, cosmos::auth::v1beta1::QueryAccountRequest,
cosmos::bank::v1beta1::QueryBalanceRequest, traits::MessageExt,
};

use bip32::{Mnemonic, XPrv};

use gotabit_sdk_proto::cosmos::auth::v1beta1::BaseAccount as BaseAcct;

const GIO_PREFIX: &'static str = "gio";

const TEST_NET_MNEMONIC: &'static str = "nose enjoy rare comic champion cancel axis chronic fringe promote shield own twenty lab decline chat light stamp open pet salon lyrics mimic pride";
Expand Down Expand Up @@ -71,86 +61,27 @@ async fn test_submit_tx() {
// create grpc client by given address
let mut client = GrpcClient::new(&TEST_NET).await.unwrap();

// query sender base_account infomation
let resp = client
.clients
.cosmos
.auth
.account(QueryAccountRequest {
address: sender_account_id.to_string(),
})
.await
.unwrap()
.into_inner();

let base_acct: BaseAccount = BaseAcct::from_any(&resp.account.unwrap()).unwrap();

// Transaction metadata: chain, account, sequence, gas, fee, timeout, and memo.
let gas = 100_000u64;
let timeout_height = 11358142;
let memo = "example memo".to_string();

// build a simple transfer transction and sign
let tx_body = TxBody {
messages: vec![msg_send.to_any().unwrap()],
memo,
timeout_height,
extension_options: Default::default(),
non_critical_extension_options: Default::default(),
};
// build a single sign
let signer_info = SignerInfo {
public_key: Some(sender_public_key.into()),
mode_info: Some(ModeInfo {
sum: Some(mode_info::Sum::Single(mode_info::Single {
mode: SignMode::Direct.into(),
})),
}),
sequence: base_acct.sequence,
};

let auth_info = AuthInfo {
signer_infos: vec![signer_info],
fee: Some(Fee {
amount: vec![coin],
gas_limit: gas,
payer: Default::default(),
granter: Default::default(),
}),
tip: None,
};

let sign_doc = SignDoc {
body_bytes: tx_body.to_bytes().unwrap(),
auth_info_bytes: auth_info.to_bytes().unwrap(),
chain_id: client.chain_id.to_string(),
account_number: base_acct.account_number,
};

let sign_doc_bytes = sign_doc.to_bytes().unwrap();
let sign = sender_private_key.sign(&sign_doc_bytes).unwrap();

let tx_raw = TxRaw {
body_bytes: sign_doc.body_bytes,
auth_info_bytes: auth_info.to_bytes().unwrap(),
signatures: vec![sign.to_vec()],
};
// broadcast signed transaction
let resp = client
.clients
.cosmos
.tx
.broadcast_tx(BroadcastTxRequest {
tx_bytes: tx_raw.to_bytes().unwrap(),
mode: BroadcastMode::Sync.into(),
})
.broadcast_tx_sync(
sender_private_key,
sender_account_id.to_string(),
msg_send,
coin,
memo,
timeout_height,
gas,
None,
)
.await
.unwrap()
.into_inner()
.tx_response
.unwrap();

assert_eq!(resp.code, 0);
let response_body = resp.into_inner().tx_response.unwrap();

assert_eq!(response_body.code, 0);
}

#[tokio::test]
Expand Down

0 comments on commit 50cddfc

Please sign in to comment.