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 {
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>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ExtrinsicInformation {
pub encoded: Option<String>,
pub tx_hash: H256,
pub tx_index: u32,
pub pallet_id: u8,
pub call_id: u8,
pub signature: Option<SignerPayload>,
}