use alloy::primitives::{Address, Bloom, Bytes, FixedBytes, B256, U256};
use serde::{Deserialize, Serialize, Serializer};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct QueryResult {
pub query: String,
pub result: ExpressionResult,
}
impl QueryResult {
pub fn new(query: String, result: ExpressionResult) -> QueryResult {
QueryResult { query, result }
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub enum ExpressionResult {
#[serde(rename = "account")]
Account(Vec<AccountQueryRes>),
#[serde(rename = "block")]
Block(Vec<BlockQueryRes>),
#[serde(rename = "transaction")]
Transaction(Vec<TransactionQueryRes>),
#[serde(rename = "log")]
Log(Vec<LogQueryRes>),
}
#[serde_with::skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct BlockQueryRes {
pub number: Option<u64>,
pub timestamp: Option<u64>,
pub hash: Option<B256>,
#[serde(serialize_with = "serialize_option_u256")]
pub size: Option<U256>,
pub parent_hash: Option<B256>,
pub state_root: Option<B256>,
pub transactions_root: Option<B256>,
pub receipts_root: Option<B256>,
pub logs_bloom: Option<Bloom>,
pub extra_data: Option<Bytes>,
pub mix_hash: Option<B256>,
pub total_difficulty: Option<U256>,
pub base_fee_per_gas: Option<u128>,
pub withdrawals_root: Option<B256>,
pub blob_gas_used: Option<u128>,
pub excess_blob_gas: Option<u128>,
pub parent_beacon_block_root: Option<B256>,
}
impl Default for BlockQueryRes {
fn default() -> Self {
Self {
number: None,
timestamp: None,
hash: None,
size: None,
parent_hash: None,
state_root: None,
transactions_root: None,
receipts_root: None,
logs_bloom: None,
extra_data: None,
mix_hash: None,
total_difficulty: None,
base_fee_per_gas: None,
withdrawals_root: None,
blob_gas_used: None,
excess_blob_gas: None,
parent_beacon_block_root: None,
}
}
}
#[serde_with::skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct AccountQueryRes {
pub nonce: Option<u64>,
#[serde(serialize_with = "serialize_option_u256")]
pub balance: Option<U256>,
pub address: Option<Address>,
pub code: Option<Bytes>,
}
impl Default for AccountQueryRes {
fn default() -> Self {
Self {
nonce: None,
balance: None,
address: None,
code: None,
}
}
}
#[serde_with::skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct TransactionQueryRes {
pub transaction_type: Option<u8>,
pub hash: Option<FixedBytes<32>>,
pub from: Option<Address>,
pub to: Option<Address>,
pub data: Option<Bytes>,
#[serde(serialize_with = "serialize_option_u256")]
pub value: Option<U256>,
pub gas_price: Option<u128>,
pub gas: Option<u128>,
pub status: Option<bool>,
pub chain_id: Option<u64>,
pub v: Option<U256>,
pub r: Option<U256>,
pub s: Option<U256>,
pub max_fee_per_blob_gas: Option<u128>,
pub max_fee_per_gas: Option<u128>,
pub max_priority_fee_per_gas: Option<u128>,
pub y_parity: Option<bool>,
}
impl Default for TransactionQueryRes {
fn default() -> Self {
Self {
transaction_type: None,
hash: None,
from: None,
to: None,
data: None,
value: None,
gas_price: None,
gas: None,
status: None,
chain_id: None,
v: None,
r: None,
s: None,
max_fee_per_blob_gas: None,
max_fee_per_gas: None,
max_priority_fee_per_gas: None,
y_parity: None,
}
}
}
#[serde_with::skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
pub struct LogQueryRes {
pub address: Option<Address>,
pub topic0: Option<FixedBytes<32>>,
pub topic1: Option<FixedBytes<32>>,
pub topic2: Option<FixedBytes<32>>,
pub topic3: Option<FixedBytes<32>>,
pub data: Option<Bytes>,
pub block_hash: Option<B256>,
pub block_number: Option<u64>,
pub block_timestamp: Option<u64>,
pub transaction_hash: Option<B256>,
pub transaction_index: Option<u64>,
pub log_index: Option<u64>,
pub removed: Option<bool>,
}
impl Default for LogQueryRes {
fn default() -> Self {
Self {
address: None,
topic0: None,
topic1: None,
topic2: None,
topic3: None,
data: None,
block_hash: None,
block_number: None,
block_timestamp: None,
transaction_hash: None,
transaction_index: None,
log_index: None,
removed: None,
}
}
}
#[cfg(test)]
mod test {
use std::str::FromStr;
use super::serialize_option_u256;
use alloy::primitives::U256;
use serde::Serialize;
use serde_json::json;
#[derive(Serialize)]
struct U256Serializable {
#[serde(serialize_with = "serialize_option_u256")]
pub value: Option<U256>,
}
#[test]
fn test_u256_serialization() {
let value = U256::from_str("100").expect("Unable to parse value to U256");
let u256 = U256Serializable { value: Some(value) };
let u256_str = json!(u256).to_string();
assert_eq!("{\"value\":\"100\"}", u256_str);
}
}
fn serialize_option_u256<S>(option: &Option<U256>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match option {
Some(u256) => serializer.serialize_some(&u256.to_string()),
None => serializer.serialize_none(),
}
}