// Copyright 2019-2022 Parity Technologies (UK) Ltd. // This file is part of subxt. // // subxt is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // subxt is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with subxt. If not, see . use codec::{ Compact, Encode, }; use crate::{ Config, Encoded, }; // We require Era as a param below, so make it available from here. pub use sp_runtime::generic::Era; /// This trait allows you to configure the "signed extra" and /// "additional" parameters that are signed and used in transactions. /// see [`BaseExtrinsicParams`] for an implementation that is compatible with /// a Polkadot node. pub trait ExtrinsicParams { /// These parameters can be provided to the constructor along with /// some default parameters that `subxt` understands, in order to /// help construct your [`ExtrinsicParams`] object. type OtherParams; /// Construct a new instance of our [`ExtrinsicParams`] fn new( spec_version: u32, tx_version: u32, nonce: T::Index, genesis_hash: T::Hash, other_params: Self::OtherParams, ) -> Self; /// This is expected to SCALE encode the "signed extra" parameters /// to some buffer that has been provided. These are the parameters /// which are sent along with the transaction, as well as taken into /// account when signing the transaction. fn encode_extra_to(&self, v: &mut Vec); /// This is expected to SCALE encode the "additional" parameters /// to some buffer that has been provided. These parameters are _not_ /// sent along with the transaction, but are taken into account when /// signing it, meaning the client and node must agree on their values. fn encode_additional_to(&self, v: &mut Vec); } /// A struct representing the signed extra and additional parameters required /// to construct a transaction for the default substrate node. pub type SubstrateExtrinsicParams = BaseExtrinsicParams; /// A builder which leads to [`SubstrateExtrinsicParams`] being constructed. /// This is what you provide to methods like `sign_and_submit()`. pub type SubstrateExtrinsicParamsBuilder = BaseExtrinsicParamsBuilder; /// A struct representing the signed extra and additional parameters required /// to construct a transaction for a polkadot node. pub type PolkadotExtrinsicParams = BaseExtrinsicParams; /// A builder which leads to [`PolkadotExtrinsicParams`] being constructed. /// This is what you provide to methods like `sign_and_submit()`. pub type PolkadotExtrinsicParamsBuilder = BaseExtrinsicParamsBuilder; /// An implementation of [`ExtrinsicParams`] that is suitable for constructing /// extrinsics that can be sent to a node with the same signed extra and additional /// parameters as a Polkadot/Substrate node. The way that tip payments are specified /// differs between Substrate and Polkadot nodes, and so we are generic over that in /// order to support both here with relative ease. /// /// If your node differs in the "signed extra" and "additional" parameters expected /// to be sent/signed with a transaction, then you can define your own type which /// implements the [`ExtrinsicParams`] trait. pub struct BaseExtrinsicParams { era: Era, nonce: T::Index, tip: Tip, spec_version: u32, transaction_version: u32, genesis_hash: T::Hash, mortality_checkpoint: T::Hash, marker: std::marker::PhantomData, } /// This builder allows you to provide the parameters that can be configured in order to /// construct a [`BaseExtrinsicParams`] value. This implements [`Default`], which allows /// [`BaseExtrinsicParams`] to be used with convenience methods like `sign_and_submit_default()`. /// /// Prefer to use [`SubstrateExtrinsicParamsBuilder`] for a version of this tailored towards /// Substrate, or [`PolkadotExtrinsicParamsBuilder`] for a version tailored to Polkadot. pub struct BaseExtrinsicParamsBuilder { era: Era, mortality_checkpoint: Option, tip: Tip, } impl BaseExtrinsicParamsBuilder { /// Instantiate the default set of [`BaseExtrinsicParamsBuilder`] pub fn new() -> Self { Self::default() } /// Set the [`Era`], which defines how long the transaction will be valid for /// (it can be either immortal, or it can be mortal and expire after a certain amount /// of time). The second argument is the block hash after which the transaction /// becomes valid, and must align with the era phase (see the [`Era::Mortal`] docs /// for more detail on that). pub fn era(mut self, era: Era, checkpoint: T::Hash) -> Self { self.era = era; self.mortality_checkpoint = Some(checkpoint); self } /// Set the tip you'd like to give to the block author /// for this transaction. pub fn tip(mut self, tip: impl Into) -> Self { self.tip = tip.into(); self } } impl Default for BaseExtrinsicParamsBuilder { fn default() -> Self { Self { era: Era::Immortal, mortality_checkpoint: None, tip: Tip::default(), } } } impl ExtrinsicParams for BaseExtrinsicParams { type OtherParams = BaseExtrinsicParamsBuilder; fn new( // Provided from subxt client: spec_version: u32, transaction_version: u32, nonce: T::Index, genesis_hash: T::Hash, // Provided externally: other_params: Self::OtherParams, ) -> Self { BaseExtrinsicParams { era: other_params.era, mortality_checkpoint: other_params .mortality_checkpoint .unwrap_or(genesis_hash), tip: other_params.tip, nonce, spec_version, transaction_version, genesis_hash, marker: std::marker::PhantomData, } } fn encode_extra_to(&self, v: &mut Vec) { let nonce: u64 = self.nonce.into(); let tip = Encoded(self.tip.encode()); (self.era, Compact(nonce), tip).encode_to(v); } fn encode_additional_to(&self, v: &mut Vec) { ( self.spec_version, self.transaction_version, self.genesis_hash, self.mortality_checkpoint, ) .encode_to(v); } } /// A tip payment. #[derive(Copy, Clone, Default, Encode)] pub struct PlainTip { #[codec(compact)] tip: u128, } impl PlainTip { /// Create a new tip of the amount provided. pub fn new(amount: u128) -> Self { PlainTip { tip: amount } } } impl From for PlainTip { fn from(n: u128) -> Self { PlainTip::new(n) } } /// A tip payment made in the form of a specific asset. #[derive(Copy, Clone, Default, Encode)] pub struct AssetTip { #[codec(compact)] tip: u128, asset: Option, } impl AssetTip { /// Create a new tip of the amount provided. pub fn new(amount: u128) -> Self { AssetTip { tip: amount, asset: None, } } /// Designate the tip as being of a particular asset class. /// If this is not set, then the native currency is used. pub fn of_asset(mut self, asset: u32) -> Self { self.asset = Some(asset); self } } impl From for AssetTip { fn from(n: u128) -> Self { AssetTip::new(n) } }