avail-rust-core 0.5.1

Avail Rust SDK core library
Documentation
use crate::{HashNumber, rpc::Error};
use primitive_types::H256;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use subxt_rpcs::{RpcClient, rpc_params};

pub async fn fetch_extrinsics_v1(
	client: &RpcClient,
	block_id: HashNumber,
	options: &Options,
) -> Result<Vec<ExtrinsicInfo>, Error> {
	let options: RpcOptions = RpcOptions {
		filter: Filter {
			transaction: Some(options.transaction_filter.clone()),
			signature: SignatureFilter {
				ss58_address: options.ss58_address.clone(),
				app_id: options.app_id,
				nonce: options.nonce,
			},
		},
		encode_selector: Some(options.encode_as),
	};

	let params = rpc_params![block_id, options];
	let value: Vec<ExtrinsicInformation> = client.request("system_fetchExtrinsicsV1", params).await?;
	let value: Vec<ExtrinsicInfo> = value.into_iter().map(|x| x.into()).collect();
	Ok(value)
}

#[derive(Debug, Default, Clone)]
pub struct Options {
	pub transaction_filter: ExtrinsicFilter,
	pub ss58_address: Option<String>,
	pub app_id: Option<u32>,
	pub nonce: Option<u32>,
	pub encode_as: EncodeSelector,
}

impl Options {
	pub fn new() -> Self {
		Self::default()
	}

	pub fn nonce(mut self, value: u32) -> Self {
		self.nonce = Some(value);
		self
	}

	pub fn app_id(mut self, value: u32) -> Self {
		self.app_id = Some(value);
		self
	}

	pub fn ss58_address(mut self, value: impl Into<String>) -> Self {
		self.ss58_address = Some(value.into());
		self
	}

	pub fn filter(mut self, value: impl Into<ExtrinsicFilter>) -> Self {
		self.transaction_filter = value.into();
		self
	}

	pub fn encode_as(mut self, value: EncodeSelector) -> Self {
		self.encode_as = value;
		self
	}
}

#[derive(Debug, Clone, Default, Copy, Serialize, Deserialize)]
#[repr(u8)]
pub enum EncodeSelector {
	None = 0,
	Call = 1,
	#[default]
	Extrinsic = 2,
}

#[derive(Debug, Clone)]
pub struct ExtrinsicInfo {
	// Hex string encoded
	pub data: Option<String>,
	pub ext_hash: H256,
	pub ext_index: u32,
	pub pallet_id: u8,
	pub variant_id: u8,
	pub signer_payload: Option<SignerPayload>,
}

impl From<ExtrinsicInformation> for ExtrinsicInfo {
	fn from(value: ExtrinsicInformation) -> Self {
		Self {
			data: value.encoded,
			ext_hash: value.tx_hash,
			ext_index: value.tx_index,
			pallet_id: value.pallet_id,
			variant_id: value.call_id,
			signer_payload: value.signature,
		}
	}
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct SignerPayload {
	pub app_id: u32,
	pub nonce: u32,
	pub ss58_address: Option<String>,
	pub mortality: Option<(u64, u64)>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ExtrinsicFilter {
	All,
	TxHash(Vec<H256>),
	TxIndex(Vec<u32>),
	Pallet(Vec<u8>),
	PalletCall(Vec<(u8, u8)>),
}

impl ExtrinsicFilter {
	pub fn new() -> Self {
		Self::default()
	}
}

impl Default for ExtrinsicFilter {
	fn default() -> Self {
		Self::All
	}
}

impl TryFrom<String> for ExtrinsicFilter {
	type Error = String;

	fn try_from(value: String) -> Result<Self, Self::Error> {
		Self::try_from(value.as_str())
	}
}

impl TryFrom<&String> for ExtrinsicFilter {
	type Error = String;

	fn try_from(value: &String) -> Result<Self, Self::Error> {
		Self::try_from(value.as_str())
	}
}

impl TryFrom<&str> for ExtrinsicFilter {
	type Error = String;

	fn try_from(value: &str) -> Result<Self, Self::Error> {
		let h256 = H256::from_str(value).map_err(|x| x.to_string())?;
		Ok(Self::TxHash(vec![h256]))
	}
}

impl From<H256> for ExtrinsicFilter {
	fn from(value: H256) -> Self {
		Self::TxHash(vec![value])
	}
}

impl From<Vec<H256>> for ExtrinsicFilter {
	fn from(value: Vec<H256>) -> Self {
		Self::TxHash(value)
	}
}

impl From<&Vec<H256>> for ExtrinsicFilter {
	fn from(value: &Vec<H256>) -> Self {
		Self::TxHash(value.clone())
	}
}

impl From<&[H256]> for ExtrinsicFilter {
	fn from(value: &[H256]) -> Self {
		Self::TxHash(value.to_vec())
	}
}

impl From<u32> for ExtrinsicFilter {
	fn from(value: u32) -> Self {
		Self::TxIndex(vec![value])
	}
}

impl From<Vec<u32>> for ExtrinsicFilter {
	fn from(value: Vec<u32>) -> Self {
		Self::TxIndex(value)
	}
}

impl From<&Vec<u32>> for ExtrinsicFilter {
	fn from(value: &Vec<u32>) -> Self {
		Self::TxIndex(value.clone())
	}
}

impl From<&[u32]> for ExtrinsicFilter {
	fn from(value: &[u32]) -> Self {
		Self::TxIndex(value.to_vec())
	}
}

impl From<u8> for ExtrinsicFilter {
	fn from(value: u8) -> Self {
		Self::Pallet(vec![value])
	}
}

impl From<&[u8]> for ExtrinsicFilter {
	fn from(value: &[u8]) -> Self {
		Self::Pallet(value.to_vec())
	}
}

impl From<Vec<u8>> for ExtrinsicFilter {
	fn from(value: Vec<u8>) -> Self {
		Self::Pallet(value)
	}
}

impl From<&Vec<u8>> for ExtrinsicFilter {
	fn from(value: &Vec<u8>) -> Self {
		Self::Pallet(value.clone())
	}
}

impl From<(u8, u8)> for ExtrinsicFilter {
	fn from(value: (u8, u8)) -> Self {
		Self::PalletCall(vec![value])
	}
}

impl From<&[(u8, u8)]> for ExtrinsicFilter {
	fn from(value: &[(u8, u8)]) -> Self {
		Self::PalletCall(value.to_vec())
	}
}

impl From<Vec<(u8, u8)>> for ExtrinsicFilter {
	fn from(value: Vec<(u8, u8)>) -> Self {
		Self::PalletCall(value)
	}
}

impl From<&Vec<(u8, u8)>> for ExtrinsicFilter {
	fn from(value: &Vec<(u8, u8)>) -> Self {
		Self::PalletCall(value.clone())
	}
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
struct RpcOptions {
	pub filter: Filter,
	pub encode_selector: Option<EncodeSelector>,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
struct Filter {
	pub transaction: Option<ExtrinsicFilter>,
	pub signature: SignatureFilter,
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
struct SignatureFilter {
	pub ss58_address: Option<String>,
	pub app_id: Option<u32>,
	pub nonce: Option<u32>,
}

// This is struct is supposed to be private but is made public
// for our tests to work.
//
// It is not dumb if it works. ¯\_(ツ)_/¯
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ExtrinsicInformation {
	// Hex string encoded
	pub encoded: Option<String>,
	pub tx_hash: H256,
	pub tx_index: u32,
	pub pallet_id: u8,
	pub call_id: u8,
	pub signature: Option<SignerPayload>,
}