pallet_example_authorization_tx_extension/
extensions.rs1use core::{fmt, marker::PhantomData};
25
26use codec::{Decode, DecodeWithMemTracking, Encode};
27use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, Parameter};
28use scale_info::TypeInfo;
29use sp_runtime::{
30 impl_tx_ext_default,
31 traits::{
32 DispatchInfoOf, DispatchOriginOf, IdentifyAccount, TransactionExtension, ValidateResult,
33 Verify,
34 },
35 transaction_validity::{InvalidTransaction, ValidTransaction},
36};
37
38use crate::pallet_coownership::{Config, Origin};
39
40#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
42pub struct AuthCredentials<Signer, Signature> {
43 first: (Signer, Signature),
44 second: (Signer, Signature),
45}
46
47#[derive(Clone, Eq, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo)]
53#[scale_info(skip_type_params(T))]
54pub struct AuthorizeCoownership<T, Signer, Signature> {
55 inner: Option<AuthCredentials<Signer, Signature>>,
56 _phantom: PhantomData<T>,
57}
58
59impl<T: Config, Signer, Signature> Default for AuthorizeCoownership<T, Signer, Signature> {
60 fn default() -> Self {
61 Self { inner: None, _phantom: Default::default() }
62 }
63}
64
65impl<T: Config, Signer, Signature> AuthorizeCoownership<T, Signer, Signature> {
66 pub fn new(first: (Signer, Signature), second: (Signer, Signature)) -> Self {
68 Self { inner: Some(AuthCredentials { first, second }), _phantom: Default::default() }
69 }
70}
71
72impl<T: Config, Signer, Signature> fmt::Debug for AuthorizeCoownership<T, Signer, Signature> {
73 #[cfg(feature = "std")]
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 write!(f, "AuthorizeCoownership")
76 }
77
78 #[cfg(not(feature = "std"))]
79 fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
80 Ok(())
81 }
82}
83
84impl<T: Config + Send + Sync, Signer, Signature> TransactionExtension<T::RuntimeCall>
85 for AuthorizeCoownership<T, Signer, Signature>
86where
87 Signer: IdentifyAccount<AccountId = T::AccountId> + Parameter + Send + Sync + 'static,
88 Signature: Verify<Signer = Signer> + Parameter + Send + Sync + 'static,
89{
90 const IDENTIFIER: &'static str = "AuthorizeCoownership";
91 type Implicit = ();
92 type Val = ();
93 type Pre = ();
94
95 fn validate(
96 &self,
97 mut origin: DispatchOriginOf<T::RuntimeCall>,
98 _call: &T::RuntimeCall,
99 _info: &DispatchInfoOf<T::RuntimeCall>,
100 _len: usize,
101 _self_implicit: Self::Implicit,
102 inherited_implication: &impl codec::Encode,
103 _source: TransactionSource,
104 ) -> ValidateResult<Self::Val, T::RuntimeCall> {
105 let Some(auth) = &self.inner else {
107 return Ok((ValidTransaction::default(), (), origin));
108 };
109 let first_account = auth.first.0.clone().into_account();
110 let second_account = auth.second.0.clone().into_account();
111
112 let msg = inherited_implication.using_encoded(sp_io::hashing::blake2_256);
114
115 if !auth.first.1.verify(&msg[..], &first_account) {
120 Err(InvalidTransaction::Custom(100))?
121 }
122 if !auth.second.1.verify(&msg[..], &second_account) {
123 Err(InvalidTransaction::Custom(200))?
124 }
125 let local_origin = Origin::Coowners(first_account, second_account);
127 let local_origin = <T as Config>::PalletsOrigin::from(local_origin);
129 let local_origin = <T as Config>::RuntimeOrigin::from(local_origin);
131 origin.set_caller_from(local_origin);
134 Ok((ValidTransaction::default(), (), origin))
136 }
137 impl_tx_ext_default!(T::RuntimeCall; weight prepare);
139}