diff --git a/core/src/config/extrinsic_params.rs b/core/src/config/extrinsic_params.rs index 1f13e45fe9..1353ec3a25 100644 --- a/core/src/config/extrinsic_params.rs +++ b/core/src/config/extrinsic_params.rs @@ -14,7 +14,7 @@ use alloc::vec::Vec; /// This trait allows you to configure the "signed extra" and /// "additional" parameters that are a part of the transaction payload /// or the signer payload respectively. -pub trait ExtrinsicParams: ExtrinsicParamsEncoder + Sized + 'static { +pub trait ExtrinsicParams: ExtrinsicParamsEncoder + Sized + Send + 'static { /// These parameters can be provided to the constructor along with /// some default parameters that `subxt` understands, in order to /// help construct your [`ExtrinsicParams`] object. diff --git a/core/src/config/mod.rs b/core/src/config/mod.rs index dc0cb7783f..2c7b484ff3 100644 --- a/core/src/config/mod.rs +++ b/core/src/config/mod.rs @@ -58,7 +58,7 @@ pub trait Config: Sized + Send + Sync + 'static { type ExtrinsicParams: ExtrinsicParams; /// This is used to identify an asset in the `ChargeAssetTxPayment` signed extension. - type AssetId: Debug + Clone + Encode + DecodeAsType + EncodeAsType; + type AssetId: Debug + Clone + Encode + DecodeAsType + EncodeAsType + Send; } /// given some [`Config`], this return the other params needed for its `ExtrinsicParams`. diff --git a/core/src/config/signed_extensions.rs b/core/src/config/signed_extensions.rs index 893872b6f2..161a255de5 100644 --- a/core/src/config/signed_extensions.rs +++ b/core/src/config/signed_extensions.rs @@ -435,7 +435,7 @@ impl SignedExtension for ChargeTransactionPayment { /// ones are actually required for the chain in the correct order, ignoring the rest. This /// is a sensible default, and allows for a single configuration to work across multiple chains. pub struct AnyOf { - params: Vec>, + params: Vec>, _marker: core::marker::PhantomData<(T, Params)>, } @@ -470,7 +470,7 @@ macro_rules! impl_tuples { // Break and record as soon as we find a match: if $ident::matches(e.identifier(), e.extra_ty(), types) { let ext = $ident::new(client, params.$index)?; - let boxed_ext: Box = Box::new(ext); + let boxed_ext: Box = Box::new(ext); exts_by_index.insert(idx, boxed_ext); break } diff --git a/subxt/examples/tx_partial.rs b/subxt/examples/tx_partial.rs new file mode 100644 index 0000000000..c463a4e64f --- /dev/null +++ b/subxt/examples/tx_partial.rs @@ -0,0 +1,53 @@ +#![allow(missing_docs)] +use subxt::{OnlineClient, PolkadotConfig}; +use subxt_signer::sr25519::dev; + +type BoxedError = Box; + +#[subxt::subxt(runtime_metadata_path = "../artifacts/polkadot_metadata_small.scale")] +pub mod polkadot {} + +#[tokio::main] +async fn main() -> Result<(), BoxedError> { + // Spawned tasks require things held across await points to impl Send, + // so we use one to demonstrate that this is possible with `PartialExtrinsic` + tokio::spawn(signing_example()).await??; + Ok(()) +} + +async fn signing_example() -> Result<(), BoxedError> { + let api = OnlineClient::::new().await?; + + // Build a balance transfer extrinsic. + let dest = dev::bob().public_key().into(); + let balance_transfer_tx = polkadot::tx().balances().transfer_allow_death(dest, 10_000); + + let alice = dev::alice(); + + // Create partial tx, ready to be signed. + let partial_tx = api + .tx() + .create_partial_signed( + &balance_transfer_tx, + &alice.public_key().to_account_id(), + Default::default(), + ) + .await?; + + // Simulate taking some time to get a signature back, in part to + // show that the `PartialExtrinsic` can be held across await points. + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + let signature = alice.sign(&partial_tx.signer_payload()); + + // Sign the transaction. + let tx = partial_tx + .sign_with_address_and_signature(&alice.public_key().to_address(), &signature.into()); + + // Submit it. + tx.submit_and_watch() + .await? + .wait_for_finalized_success() + .await?; + + Ok(()) +} diff --git a/subxt/src/book/usage/transactions.rs b/subxt/src/book/usage/transactions.rs index b263f5ae8a..b897790599 100644 --- a/subxt/src/book/usage/transactions.rs +++ b/subxt/src/book/usage/transactions.rs @@ -205,6 +205,15 @@ #![doc = include_str!("../../../examples/tx_status_stream.rs")] //! ``` //! +//! ### 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 +#![doc = include_str!("../../../examples/tx_partial.rs")] +//! ``` +//! //! Take a look at the API docs for [`crate::tx::TxProgress`], [`crate::tx::TxStatus`] and //! [`crate::tx::TxInBlock`] for more options. //!