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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// Copyright 2019-2025 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! # Transactions
//!
//! A transaction is an extrinsic that's signed (ie it originates from a given address). The purpose
//! of extrinsics is to modify the node storage in a deterministic way, and so being able to submit
//! transactions to a node is one of the core features of Subxt.
//!
//! > Note: the documentation tends to use the terms _extrinsic_ and _transaction_ interchangeably;
//! > An extrinsic is some data that can be added to a block, and is either signed (a _transaction_)
//! > or unsigned (an _inherent_). Subxt can construct either, but overwhelmingly you'll need to
//! > sign the payload you'd like to submit.
//!
//! Submitting a transaction to a node consists of the following steps:
//!
//! 1. [Constructing a transaction payload to submit](#constructing-a-transaction-payload).
//! 2. [Signing it](#signing-it).
//! 3. [Submitting it (optionally with some additional parameters)](#submitting-it).
//!
//! We'll look at each of these steps in turn.
//!
//! ## Constructing a transaction payload
//!
//! We can use the statically generated interface to build transaction payloads:
//!
//! ```rust,no_run,standalone_crate
//! #[pezkuwi_subxt::subxt(runtime_metadata_path = "../artifacts/pezkuwi_metadata_small.scale")]
//! pub mod pezkuwi {}
//!
//! let remark = "Hello there".as_bytes().to_vec();
//! let tx_payload = pezkuwi::tx().system().remark(remark);
//! ```
//!
//! > If you're not sure what types to import and use to build a given payload, you can use the
//! > `subxt` CLI tool to generate the interface by using something like `subxt codegen | rustfmt >
//! > interface.rs`, to see what types and things are available (or even just to use directly
//! > instead of the [`#[subxt]`](crate::subxt) macro).
//!
//! Alternately, we can dynamically construct a transaction payload. This will not be type checked
//! or validated until it's submitted:
//!
//! ```rust,no_run,standalone_crate
//! use pezkuwi_subxt::dynamic::Value;
//!
//! let tx_payload = pezkuwi_subxt::dynamic::tx("System", "remark", vec![
//! Value::from_bytes("Hello there")
//! ]);
//! ```
//!
//! The [`crate::dynamic::Value`] type is a dynamic type much like a `serde_json::Value` but instead
//! represents any type of data that can be SCALE encoded or decoded. It can be serialized,
//! deserialized and parsed from/to strings.
//!
//! A valid transaction payload is just something that implements the [`crate::tx::Payload`] trait;
//! you can implement this trait on your own custom types if the built-in ones are not suitable for
//! your needs.
//!
//! ## Signing it
//!
//! You'll normally need to sign an extrinsic to prove that it originated from an account that you
//! control. To do this, you will typically first create a [`crate::tx::Signer`] instance, which
//! tells Subxt who the extrinsic is from, and takes care of signing the relevant details to prove
//! this.
//!
//! There are two main ways to create a compatible signer instance:
//! 1. The `pezkuwi_subxt_signer` crate provides a WASM compatible implementation of
//! [`crate::tx::Signer`]
//! for chains which require sr25519 or ecdsa signatures (requires the `subxt` feature to be
//! enabled).
//! 2. Alternately, implement your own [`crate::tx::Signer`] instance by wrapping it in a new type
//! pattern.
//!
//! Going for 1 leads to fewer dependencies being imported and WASM compatibility out of the box via
//! the `web` feature flag. Going for 2 is useful if you're already using the Bizinikiwi dependencies
//! or need additional signing algorithms that `pezkuwi_subxt_signer` doesn't support, and don't
//! care about WASM compatibility.
//!
//! Because 2 is more complex and require more code, we'll focus on 1 here.
//! For 2, see the example in `subxt/examples/bizinikiwi_compat_signer.rs` how
//! you can integrate things like sp_core's signer in subxt.
//!
//! Let's go through how to create a signer using the `pezkuwi_subxt_signer` crate:
//!
//! ```rust,standalone_crate
//! use pezkuwi_subxt::config::PezkuwiConfig;
//! use std::str::FromStr;
//!
//! use pezkuwi_subxt_signer::{SecretUri, sr25519};
//!
//! // Get hold of a `Signer` for a test account:
//! let alice = sr25519::dev::alice();
//!
//! // Or generate a keypair, here from an SURI:
//! let uri = SecretUri::from_str("vessel ladder alter error federal sibling chat ability sun glass valve picture/0/1///Password")
//! .expect("valid URI");
//! let keypair = sr25519::Keypair::from_uri(&uri)
//! .expect("valid keypair");
//! ```
//!
//! After initializing the signer, let's also go through how to create a transaction and sign it:
//!
//! ```rust,no_run,standalone_crate
//! # #[tokio::main]
//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use pezkuwi_subxt::client::OnlineClient;
//! use pezkuwi_subxt::config::PezkuwiConfig;
//! use pezkuwi_subxt::dynamic::Value;
//!
//! // Create client:
//! let client = OnlineClient::<PezkuwiConfig>::new().await?;
//!
//! // Create a dummy tx payload to sign:
//! let payload = pezkuwi_subxt::dynamic::tx("System", "remark", vec![
//! Value::from_bytes("Hello there")
//! ]);
//!
//! // Construct the tx but don't sign it. The account nonce here defaults to 0.
//! // You can use `create_partial` to fetch the correct nonce.
//! let mut partial_tx = client.tx().create_partial_offline(
//! &payload,
//! Default::default()
//! )?;
//!
//! // Fetch the payload that needs to be signed:
//! let signer_payload = partial_tx.signer_payload();
//!
//! // ... At this point, we can hand off the `signer_payload` to be signed externally.
//! // Ultimately we need to be given back a `signature` (or really, anything
//! // that can be SCALE encoded) and an `address`:
//! let signature;
//! let account_id;
//! # use pezkuwi_subxt::tx::Signer;
//! # let signer = pezkuwi_subxt_signer::sr25519::dev::alice();
//! # signature = signer.sign(&signer_payload).into();
//! # account_id = signer.public_key().to_account_id();
//!
//! // Now we can build an tx, which one can call `submit` or `submit_and_watch`
//! // on to submit to a node and optionally watch the status.
//! let tx = partial_tx.sign_with_account_and_signature(
//! &account_id,
//! &signature
//! );
//! # Ok(())
//! # }
//! ```
//!
//! ## Submitting it
//!
//! Once we have signed the transaction, we need to submit it.
//!
//! ### The high level API
//!
//! The highest level approach to doing this is to call
//! [`crate::tx::TxClient::sign_and_submit_then_watch_default`]. This hands back a
//! [`crate::tx::TxProgress`] struct which will monitor the transaction status. We can then call
//! [`crate::tx::TxProgress::wait_for_finalized_success()`] to wait for this transaction to make it
//! into a finalized block, check for an `ExtrinsicSuccess` event, and then hand back the events for
//! inspection. This looks like:
//!
//! ```rust,ignore
//! ```
//!
//! ### Providing transaction parameters
//!
//! If you'd like to provide parameters (such as mortality) to the transaction, you can use
//! [`crate::tx::TxClient::sign_and_submit_then_watch`] instead:
//! ```rust,ignore
//! ```
//!
//! This example doesn't wait for the transaction to be included in a block; it just submits it and
//! hopes for the best!
//!
//! ### Boxing transaction payloads
//!
//! Transaction payloads can be boxed so that they all share a common type and can be stored together.
//! ```rust,ignore
//! ```
//!
//! ### Custom handling of transaction status updates
//!
//! If you'd like more control or visibility over exactly which status updates are being emitted for
//! the transaction, you can monitor them as they are emitted and react however you choose:
//! ```rust,ignore
//! ```
//!
//! ### Signing transactions externally
//!
//! Subxt also allows you to get hold of the signer payload and hand that off to something else to be
//! signed. The signature can then be provided back to Subxt to build the final transaction to submit:
//! ```rust,ignore
//! ```
//!
//! Take a look at the API docs for [`crate::tx::TxProgress`], [`crate::tx::TxStatus`] and
//! [`crate::tx::TxInBlock`] for more options.