use scale::Encode; use sp_core::sr25519::{Public, Signature}; use sp_runtime::traits::Verify; use crate::SeraiAddress; trait TransactionMember: Clone + PartialEq + Eq + core::fmt::Debug + scale::Encode + scale::Decode + scale_info::TypeInfo { } impl< T: Clone + PartialEq + Eq + core::fmt::Debug + scale::Encode + scale::Decode + scale_info::TypeInfo, > TransactionMember for T { } #[allow(private_bounds)] #[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)] pub struct Transaction { pub call: Call, pub signature: Option<(SeraiAddress, Signature, Extra)>, } #[cfg(feature = "serde")] mod _serde { use scale::Encode; use serde::{ser::*, de::*}; use super::*; impl Serialize for Transaction { fn serialize(&self, serializer: S) -> Result { let encoded = self.encode(); serializer.serialize_bytes(&encoded) } } #[cfg(feature = "std")] impl<'a, Call: TransactionMember, Extra: TransactionMember> Deserialize<'a> for Transaction { fn deserialize>(de: D) -> Result { let bytes = sp_core::bytes::deserialize(de)?; scale::Decode::decode(&mut &bytes[..]) .map_err(|e| serde::de::Error::custom(format!("invalid transaction: {}", e))) } } } impl sp_runtime::traits::Extrinsic for Transaction { type Call = Call; type SignaturePayload = (SeraiAddress, Signature, Extra); fn is_signed(&self) -> Option { Some(self.signature.is_some()) } fn new(call: Call, signature: Option) -> Option { Some(Self { call, signature }) } } impl frame_support::traits::ExtrinsicCall for Transaction { fn call(&self) -> &Call { &self.call } } impl sp_runtime::traits::ExtrinsicMetadata for Transaction where Extra: sp_runtime::traits::SignedExtension, { type SignedExtensions = Extra; const VERSION: u8 = 0; } impl frame_support::dispatch::GetDispatchInfo for Transaction where Call: frame_support::dispatch::GetDispatchInfo, { fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo { self.call.get_dispatch_info() } } impl sp_runtime::traits::BlindCheckable for Transaction where Extra: sp_runtime::traits::SignedExtension, { type Checked = sp_runtime::generic::CheckedExtrinsic; fn check( self, ) -> Result { Ok(match self.signature { Some((signer, signature, extra)) => { if !signature.verify( (&self.call, &extra, extra.additional_signed()?).encode().as_slice(), &signer.into(), ) { Err(sp_runtime::transaction_validity::InvalidTransaction::BadProof)? } sp_runtime::generic::CheckedExtrinsic { signed: Some((signer.into(), extra)), function: self.call, } } None => sp_runtime::generic::CheckedExtrinsic { signed: None, function: self.call }, }) } }