1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//! ⚠️ This project is heavily work-in-progress and not ready for production => **API breakage expected!**
//!
//! Gekko offers utilities to parse substrate metadata, generate the
//! corresponding Rust interfaces, create transactions and the ability to
//! encode/decode those transaction.
//!
//! The project is split into multiple crates, although all functionality can be
//! exposed by just using `gekko`.
//! * `gekko` - Contains runtime interfaces to interact with Kusama, Polkadot
//!   and Westend, including creating transactions.
//! * `gekko-metadata` - Utilities to parse and process substrate metadata.
//!   * Can also be enabled in `gekko` with the `"metadata"` feature.
//! * `gekko-generator` - Macro to generate Rust interfaces during compile time
//!   based on the the parsed substrate metadata.
//!   * Can also be enabled in `gekko` with the `"generator"` feature.
//!
//! # Interacting with the runtime
//!
//! Gekko exposes multiple interfaces to interact with Kusama/Polkadot, such as
//! extrinsics, storage entires, events, constants and errors.
//!
//! ### Disclaimer about types
//!
//! This library makes no assumptions about parameter types and must be
//! specified manually as generic types. Each field contains a type description
//! which can serve as a hint on what type is being expected, as provided by the
//! runtime meatadata. See the [`common`] module for common types which can be
//! used.
//!
//! ## Extrinsics.
//!
//! Transactions can be created by using a transaction builder from the
//! [`transaction`] module. The transaction formats are versioned, reflecting
//! the changes during Substrates history. Unless you're working with historic
//! data, you probably want the latest version.
//!
//! Extrinsics can chosen from the [`runtime`] module and constructed
//! accordingly. Take a look at the [`common`] module which contains utilities
//! for creating transaction.
//!
//! ###  Example
//!
//! ```
//! use gekko::common::*;
//! use gekko::transaction::*;
//! use gekko::runtime::polkadot::extrinsics::balances::TransferKeepAlive;
//!
//! // In this example, a random key is generated. You probably want to *import* one.
//! let (keypair, _) = KeyPairBuilder::<Sr25519>::generate();
//! let currency = BalanceBuilder::new(Currency::Polkadot);
//!
//! // The destination address.
//! let destination =
//!     AccountId::from_ss58_address("12eDex4amEwj39T7Wz4Rkppb68YGCDYKG9QHhEhHGtNdDy7D")
//!         .unwrap();
//!
//! // Send 50 DOT to the destination.
//! let call = TransferKeepAlive {
//!     dest: destination,
//!     value: currency.balance(50),
//! };
//!
//! // Transaction fee.
//! let payment = currency.balance_as_metric(Metric::Milli, 10).unwrap();
//!
//! // Build the final transaction.
//! let transaction: PolkadotSignedExtrinsic<_> = SignedTransactionBuilder::new()
//!     .signer(keypair)
//!     .call(call)
//!     .nonce(0)
//!     .payment(payment)
//!     .network(Network::Polkadot)
//!     .spec_version(9050)
//!     .build()
//!     .unwrap();
//! ```
//!
//! # Parsing Metadata
//!
//! Gekko offers utilities that allow you to search for specific extrinsics or
//! to iterate through all of those.
//!
//! ## Example
//!
//! ```no_run
//! use gekko::metadata::*;
//!
//! // Parse runtime metadata
//! let content = std::fs::read_to_string("metadata_kusama_9080.hex").unwrap();
//! let data = parse_hex_metadata(content).unwrap().into_inner();
//!
//! // Get information about the extrinsic.
//! let extr = data
//!     .find_module_extrinsic("Balances", "transfer_keep_alive")
//!     .unwrap();
//!
//! assert_eq!(extr.module_id, 4);
//! assert_eq!(extr.dispatch_id, 3);
//! assert_eq!(
//!     extr.args,
//!     vec![
//!         ("dest", "<T::Lookup as StaticLookup>::Source"),
//!         ("value", "Compact<T::Balance>"),
//!     ]
//! );
//! ```
//!
//! A macro available in `gekko::generator` will parse the metadata
//! automatically for you and generate the Rust interfaces at compile time.

pub use runtime::*;

#[cfg(feature = "dumps")]
/// Raw Kusama and Polkadot runtime metadata dumps.
pub mod dumps {
    pub use gekko_metadata::*;
}

#[cfg(feature = "generator")]
/// Substrate runtime metadata generator for creating Rust interfaces.
pub mod generator {
    pub use gekko_generator::*;
}

#[cfg(feature = "metadata")]
/// Utilities for parsing substrate runtime metadata.
pub mod metadata {
    pub use gekko_metadata::*;
}

pub mod transaction;
// TODO: Rename to "primitives"?
pub mod common;

/// Types and interfaces to interact with runtimes.
pub mod runtime {
    pub mod polkadot {
        pub use latest::*;

        /// The latest runtime types and interfaces.
        mod latest {
            /// The latest spec version.
            pub const SPEC_VERSION: u32 = 9050;

            #[gekko_generator::parse_from_hex_file("dumps/metadata_polkadot_9050.hex")]
            struct A;
        }
    }

    pub mod kusama {
        pub use latest::*;

        /// The latest runtime types and interfaces.
        mod latest {
            /// The latest spec version.
            pub const SPEC_VERSION: u32 = 9080;

            #[gekko_generator::parse_from_hex_file("dumps/metadata_kusama_9080.hex")]
            struct A;
        }
    }
}

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Clone)]
pub enum Error {
    BuilderMissingField(&'static str),
}

/// Convenience function for crate internals.
// TODO: Move this to `common::crypto`
fn blake2b<T: AsRef<[u8]>>(payload: T) -> [u8; 32] {
    let mut hash = [0; 32];
    hash.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], payload.as_ref()).as_bytes());
    hash
}