use core::{fmt, marker::PhantomData};
use codec::{Decode, Encode};
use frame_support::{pallet_prelude::TransactionSource, traits::OriginTrait, Parameter};
use scale_info::TypeInfo;
use sp_runtime::{
impl_tx_ext_default,
traits::{
DispatchInfoOf, DispatchOriginOf, IdentifyAccount, TransactionExtension, ValidateResult,
Verify,
},
transaction_validity::{InvalidTransaction, ValidTransaction},
};
use crate::pallet_coownership::{Config, Origin};
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct AuthCredentials<Signer, Signature> {
first: (Signer, Signature),
second: (Signer, Signature),
}
#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct AuthorizeCoownership<T, Signer, Signature> {
inner: Option<AuthCredentials<Signer, Signature>>,
_phantom: PhantomData<T>,
}
impl<T: Config, Signer, Signature> Default for AuthorizeCoownership<T, Signer, Signature> {
fn default() -> Self {
Self { inner: None, _phantom: Default::default() }
}
}
impl<T: Config, Signer, Signature> AuthorizeCoownership<T, Signer, Signature> {
pub fn new(first: (Signer, Signature), second: (Signer, Signature)) -> Self {
Self { inner: Some(AuthCredentials { first, second }), _phantom: Default::default() }
}
}
impl<T: Config, Signer, Signature> fmt::Debug for AuthorizeCoownership<T, Signer, Signature> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AuthorizeCoownership")
}
#[cfg(not(feature = "std"))]
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl<T: Config + Send + Sync, Signer, Signature> TransactionExtension<T::RuntimeCall>
for AuthorizeCoownership<T, Signer, Signature>
where
Signer: IdentifyAccount<AccountId = T::AccountId> + Parameter + Send + Sync + 'static,
Signature: Verify<Signer = Signer> + Parameter + Send + Sync + 'static,
{
const IDENTIFIER: &'static str = "AuthorizeCoownership";
type Implicit = ();
type Val = ();
type Pre = ();
fn validate(
&self,
mut origin: DispatchOriginOf<T::RuntimeCall>,
_call: &T::RuntimeCall,
_info: &DispatchInfoOf<T::RuntimeCall>,
_len: usize,
_self_implicit: Self::Implicit,
inherited_implication: &impl codec::Encode,
_source: TransactionSource,
) -> ValidateResult<Self::Val, T::RuntimeCall> {
let Some(auth) = &self.inner else {
return Ok((ValidTransaction::default(), (), origin));
};
let first_account = auth.first.0.clone().into_account();
let second_account = auth.second.0.clone().into_account();
let msg = inherited_implication.using_encoded(sp_io::hashing::blake2_256);
if !auth.first.1.verify(&msg[..], &first_account) {
Err(InvalidTransaction::Custom(100))?
}
if !auth.second.1.verify(&msg[..], &second_account) {
Err(InvalidTransaction::Custom(200))?
}
let local_origin = Origin::Coowners(first_account, second_account);
let local_origin = <T as Config>::PalletsOrigin::from(local_origin);
let local_origin = <T as Config>::RuntimeOrigin::from(local_origin);
origin.set_caller_from(local_origin);
Ok((ValidTransaction::default(), (), origin))
}
impl_tx_ext_default!(T::RuntimeCall; weight prepare);
}