use crate::{
config::{
transaction_extensions::{ChargeAssetTxPayment, ChargeTransactionPayment, CheckNonce},
Config, TransactionExtension,
},
dynamic::Value,
error::ExtrinsicError,
Metadata,
};
use alloc::borrow::ToOwned;
use frame_decode::extrinsics::ExtrinsicExtensions;
use scale_decode::DecodeAsType;
#[derive(Debug, Clone)]
pub struct ExtrinsicTransactionExtensions<'a, T: Config> {
bytes: &'a [u8],
metadata: &'a Metadata,
decoded_info: &'a ExtrinsicExtensions<'static, u32>,
_marker: core::marker::PhantomData<T>,
}
impl<'a, T: Config> ExtrinsicTransactionExtensions<'a, T> {
pub(crate) fn new(
bytes: &'a [u8],
metadata: &'a Metadata,
decoded_info: &'a ExtrinsicExtensions<'static, u32>,
) -> Self {
Self { bytes, metadata, decoded_info, _marker: core::marker::PhantomData }
}
pub fn iter(&self) -> impl Iterator<Item = ExtrinsicTransactionExtension<'a, T>> + use<'a, T> {
self.decoded_info.iter().map(|s| ExtrinsicTransactionExtension {
bytes: &self.bytes[s.range()],
ty_id: *s.ty(),
identifier: s.name(),
metadata: self.metadata,
_marker: core::marker::PhantomData,
})
}
pub fn find<S: TransactionExtension<T>>(&self) -> Result<Option<S::Decoded>, ExtrinsicError> {
for ext in self.iter() {
match ext.as_signed_extension::<S>() {
Ok(Some(e)) => return Ok(Some(e)),
Ok(None) => continue,
Err(e) => return Err(e),
}
}
Ok(None)
}
pub fn tip(&self) -> Option<u128> {
self.find::<ChargeTransactionPayment>()
.ok()
.flatten()
.map(|e| e.tip())
.or_else(|| self.find::<ChargeAssetTxPayment<T>>().ok().flatten().map(|e| e.tip()))
}
pub fn nonce(&self) -> Option<u64> {
self.find::<CheckNonce>().ok()?
}
}
#[derive(Debug, Clone)]
pub struct ExtrinsicTransactionExtension<'a, T: Config> {
bytes: &'a [u8],
ty_id: u32,
identifier: &'a str,
metadata: &'a Metadata,
_marker: core::marker::PhantomData<T>,
}
impl<'a, T: Config> ExtrinsicTransactionExtension<'a, T> {
pub fn bytes(&self) -> &'a [u8] {
self.bytes
}
pub fn name(&self) -> &'a str {
self.identifier
}
pub fn type_id(&self) -> u32 {
self.ty_id
}
pub fn value(&self) -> Result<Value<u32>, ExtrinsicError> {
let value = scale_value::scale::decode_as_type(
&mut &self.bytes[..],
self.ty_id,
self.metadata.types(),
)
.map_err(|e| ExtrinsicError::CouldNotDecodeTransactionExtension {
name: self.identifier.to_owned(),
error: e.into(),
})?;
Ok(value)
}
pub fn as_signed_extension<S: TransactionExtension<T>>(
&self,
) -> Result<Option<S::Decoded>, ExtrinsicError> {
if !S::matches(self.identifier, self.ty_id, self.metadata.types()) {
return Ok(None);
}
self.as_type::<S::Decoded>().map(Some)
}
fn as_type<E: DecodeAsType>(&self) -> Result<E, ExtrinsicError> {
let value = E::decode_as_type(&mut &self.bytes[..], self.ty_id, self.metadata.types())
.map_err(|e| ExtrinsicError::CouldNotDecodeTransactionExtension {
name: self.identifier.to_owned(),
error: e,
})?;
Ok(value)
}
}