diff --git a/pallets/pass/src/extension.rs b/pallets/pass/src/extension.rs index 4b8205c..798e7f5 100644 --- a/pallets/pass/src/extension.rs +++ b/pallets/pass/src/extension.rs @@ -4,9 +4,14 @@ use codec::{Decode, Encode}; use frame_support::pallet_prelude::TransactionValidityError; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::traits::{DispatchInfoOf, SignedExtension}; - use crate::{Config, Pallet}; +/// Changes the origin account to inner extensions if the signer is a session key, so the validations +/// and handling of these extensions (like charging to an account) happens on behalf of the `AccountId` +/// of the account this session key is being associated to. +/// +/// In the future, this extension would be deprecated in favour of a couple of an extension that issues +/// authorized origins from `pallet-pass`. #[derive(Encode, Decode)] pub struct ChargeTransactionToPassAccount(S, PhantomData<(T, I)>); @@ -30,7 +35,7 @@ impl PartialEq for ChargeTransactionToPassAccount { } impl TypeInfo - for ChargeTransactionToPassAccount +for ChargeTransactionToPassAccount { type Identity = S; fn type_info() -> scale_info::Type { @@ -39,7 +44,7 @@ impl TypeInfo } impl core::fmt::Debug - for ChargeTransactionToPassAccount +for ChargeTransactionToPassAccount { #[cfg(feature = "std")] fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { @@ -55,7 +60,7 @@ impl SignedExtension for ChargeTransactionToPassAccount where T: Config + Send + Sync, I: 'static + Send + Sync, - S: SignedExtension::RuntimeCall>, + S: SignedExtension::RuntimeCall>, { const IDENTIFIER: &'static str = S::IDENTIFIER; type AccountId = S::AccountId; @@ -67,6 +72,17 @@ where self.0.additional_signed() } + fn validate( + &self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> frame_support::pallet_prelude::TransactionValidity { + let who = Pallet::::signer_from_session_key(who).unwrap_or(who.clone()); + self.0.validate(&who, call, info, len) + } + fn pre_dispatch( self, who: &Self::AccountId, @@ -78,6 +94,86 @@ where self.0.pre_dispatch(&who, call, info, len) } + fn post_dispatch( + pre: Option, + info: &DispatchInfoOf, + post_info: &sp_runtime::traits::PostDispatchInfoOf, + len: usize, + result: &sp_runtime::DispatchResult, + ) -> Result<(), frame_support::pallet_prelude::TransactionValidityError> { + S::post_dispatch(pre, info, post_info, len, result) + } +} + +/// Skips some checks (like [`frame_system::CheckNonce`]) if the caller is a session key. +/// +/// This extension should be deprecated in the future in favour of a couple of `TransactionExtension`s +/// that: +/// +/// 1. Issues a new custom origin from `pallet-pass` to wrap the account and skip checks. Then, +/// 2. After those checks, replaces this custom origin with [`frame_system::RawOrigin::Signed`], +/// where the signed `account_id` is the derived `AccountId` associated to the account handled by +/// `pallet-pass`. +#[derive(Encode, Decode)] +pub struct SkipCheckIfPassAccount(S, PhantomData<(T, I)>); + +impl SkipCheckIfPassAccount { + pub fn new(s: S) -> Self { + Self(s, PhantomData) + } +} + +impl Clone for SkipCheckIfPassAccount { + fn clone(&self) -> Self { + Self(self.0.clone(), PhantomData) + } +} + +impl Eq for SkipCheckIfPassAccount {} +impl PartialEq for SkipCheckIfPassAccount { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl TypeInfo +for SkipCheckIfPassAccount +{ + type Identity = S; + fn type_info() -> scale_info::Type { + S::type_info() + } +} + +impl core::fmt::Debug +for SkipCheckIfPassAccount +{ + #[cfg(feature = "std")] + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "SkipCheckIfPassAccount<{:?}>", self.0.encode()) + } + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result { + Ok(()) + } +} + +impl SignedExtension for SkipCheckIfPassAccount +where + T: Config + Send + Sync, + I: 'static + Send + Sync, + S: SignedExtension::RuntimeCall>, +{ + const IDENTIFIER: &'static str = S::IDENTIFIER; + type AccountId = S::AccountId; + type Call = S::Call; + type AdditionalSigned = S::AdditionalSigned; + type Pre = S::Pre; + + fn additional_signed(&self) -> Result { + self.0.additional_signed() + } + fn validate( &self, who: &Self::AccountId, @@ -85,10 +181,25 @@ where info: &DispatchInfoOf, len: usize, ) -> frame_support::pallet_prelude::TransactionValidity { - let who = Pallet::::signer_from_session_key(who).unwrap_or(who.clone()); + if Pallet::::signer_from_session_key(who).is_some() { + return Ok(Default::default()); + } self.0.validate(&who, call, info, len) } + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &DispatchInfoOf, + len: usize, + ) -> Result { + if Pallet::::signer_from_session_key(who).is_some() { + return Ok((None, Default::default())); + } + self.0.pre_dispatch(&who, call, info, len) + } + fn post_dispatch( pre: Option, info: &DispatchInfoOf, @@ -96,6 +207,10 @@ where len: usize, result: &sp_runtime::DispatchResult, ) -> Result<(), frame_support::pallet_prelude::TransactionValidityError> { - S::post_dispatch(pre, info, post_info, len, result) + if let Some(pre) = pre { + S::post_dispatch(pre, info, post_info, len, result) + } else { + Ok(()) + } } }