stdtx/
lib.rs

1//! Extensible schema-driven builder, signer, and Amino serializer for
2//! Cosmos SDK-formatted `StdTx` transactions, the standard transaction format
3//! used by the Cosmos SDK and other Tendermint blockchains which use types
4//! from the Cosmos SDK.
5//!
6//! Uses a TOML-based schema description language for `sdk.Msg` values which
7//! should be encoded into the final `StdTx`.
8//!
9//! Includes a `StdTx` builder capable of constructing `sdk.Msg` values and
10//! signing them using any ECDSA secp256k1 signer compatible with the
11//! [`ecdsa` crate] (e.g. [`signatory-secp256k1`], [`yubihsm`]).
12//!
13//! # Equivalent Go code
14//!
15//! - [`StdTx` (godoc)](https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth/types#StdTx)
16//! - [`sdk.Msg` (godoc)](httpshttps://docs.rs/ecdsa://godoc.org/github.com/cosmos/cosmos-sdk/types#Msg)
17//!
18//! # Usage
19//!
20//! Below is a self-contained example of how to use [`stdtx::Builder`]
21//! type to construct a signed [`StdTx`] message:
22//!
23//! ```
24//! # #[cfg(feature = "amino")]
25//! # {
26//! use stdtx::{amino::Builder, error::Result};
27//! use k256::ecdsa::SigningKey;
28//! use rand_core::OsRng; // requires `std` feature of `rand_core`
29//!
30//! /// Example account number
31//! const ACCOUNT_NUMBER: u64 = 946827;
32//!
33//! /// Example chain ID
34//! const CHAIN_ID: &str = "columbus-3";
35//!
36//! /// Example oracle feeder for `oracle/MsgExchangeRateVote`
37//! const FEEDER: &str = "terra1t9et8wjeh8d0ewf4lldchterxsmhpcgg5auy47";
38//!
39//! /// Example oracle validator for `oracle/MsgExchangeRateVote`
40//! const VALIDATOR: &str = "terravaloper1grgelyng2v6v3t8z87wu3sxgt9m5s03x2mfyu7";
41//!
42//! /// Example amount of gas to include in transaction
43//! const GAS_AMOUNT: u64 = 200000;
44//!
45//! /// Example StdTx message schema definition. See docs for the
46//! /// `stdtx::Schema` type for more information:
47//! /// <https://docs.rs/cosmos-stdtx/latest/stdtx/schema/index.html>
48//! ///
49//! /// Message types taken from Terra's oracle voter transactions:
50//! /// <https://docs.terra.money/docs/dev-spec-oracle#message-types>
51//! pub const TERRA_SCHEMA: &str = r#"
52//!     namespace = "core/StdTx"
53//!     acc_prefix = "terra"
54//!     val_prefix = "terravaloper"
55//!
56//!     [[definition]]
57//!     type_name = "oracle/MsgExchangeRatePrevote"
58//!     fields = [
59//!         { name = "hash",  type = "string" },
60//!         { name = "denom", type = "string" },
61//!         { name = "feeder", type = "sdk.AccAddress" },
62//!         { name = "validator", type = "sdk.ValAddress" },
63//!     ]
64//!
65//!     [[definition]]
66//!     type_name = "oracle/MsgExchangeRateVote"
67//!     fields = [
68//!         { name = "exchange_rate", type = "sdk.Dec"},
69//!         { name = "salt", type = "string" },
70//!         { name = "denom", type = "string" },
71//!         { name = "feeder", type = "sdk.AccAddress" },
72//!         { name = "validator", type = "sdk.ValAddress" },
73//!     ]
74//!     "#;
75//!
76//! /// Simple builder for an `oracle/MsgExchangeRateVote` message
77//! fn build_vote_msg(schema: &stdtx::amino::Schema) -> Result<stdtx::amino::Msg> {
78//!     Ok(stdtx::amino::msg::Builder::new(schema, "oracle/MsgExchangeRateVote")?
79//!         .decimal("exchange_rate", -1i8)?
80//!         .string("salt", "XXXX")?
81//!         .string("denom", "ukrw")?
82//!         .acc_address_bech32("feeder", FEEDER)?
83//!         .val_address_bech32("validator", VALIDATOR)?
84//!         .to_msg())
85//! }
86//!
87//! /// Parse the TOML schema for Terra `sdk.Msg` types
88//! let schema = TERRA_SCHEMA.parse::<stdtx::amino::Schema>().unwrap();
89//!
90//! /// Create message builder, giving it an account number, chain ID, and a
91//! /// boxed ECDSA secp256k1 signer
92//! let builder = stdtx::amino::Builder::new(schema, CHAIN_ID, ACCOUNT_NUMBER);
93//!
94//! /// Create ECDSA signing key (ordinarily you wouldn't generate a random key
95//! /// every time but reuse an existing one)
96//! let signer = SigningKey::random(&mut OsRng);
97//!
98//! /// Create message to be included in the `StdTx` using the method defined above
99//! let msg = build_vote_msg(builder.schema()).unwrap();
100//!
101//! /// Build transaction, returning serialized Amino bytes as a `Vec<u8>`
102//! let sequence_number = 123456;
103//! let fee = stdtx::amino::StdFee::for_gas(GAS_AMOUNT);
104//! let memo = "";
105//! let amino_bytes = builder
106//!     .sign_amino_tx(&signer, sequence_number, fee, memo, &[msg])
107//!     .unwrap();
108//!
109//! // `amino_bytes` is now a `Vec<u8>` containing an Amino serialized transaction
110//! # }
111//! ```
112//!
113//! [`ecdsa` crate]: https://docs.rs/ecdsa
114//! [`signatory-secp256k1`]: https://docs.rs/signatory-secp256k1
115//! [`yubihsm`]: https://docs.rs/yubihsm
116//! [`stdtx::Builder`]: https://docs.rs/stdtx/latest/stdtx/stdtx/struct.Builder.html
117
118#![doc(html_root_url = "https://docs.rs/stdtx/0.6.0")]
119#![forbid(unsafe_code)]
120#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
121
122pub mod address;
123pub mod amino;
124pub mod decimal;
125pub mod error;
126
127pub use self::{address::Address, decimal::Decimal, error::Error};
128pub use k256::ecdsa::{Signature, VerifyingKey};
129
130/// Transaction signer for ECDSA/secp256k1 signatures
131pub type Signer = dyn ecdsa::signature::Signer<Signature>;