anvil_core/eth/
serde_helpers.rs

1//! custom serde helper functions
2
3pub mod sequence {
4    use serde::{
5        de::DeserializeOwned, ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer,
6    };
7
8    pub fn serialize<S, T>(val: &T, s: S) -> Result<S::Ok, S::Error>
9    where
10        S: Serializer,
11        T: Serialize,
12    {
13        let mut seq = s.serialize_seq(Some(1))?;
14        seq.serialize_element(val)?;
15        seq.end()
16    }
17
18    pub fn deserialize<'de, T, D>(d: D) -> Result<T, D::Error>
19    where
20        D: Deserializer<'de>,
21        T: DeserializeOwned,
22    {
23        let mut seq = Vec::<T>::deserialize(d)?;
24        if seq.len() != 1 {
25            return Err(serde::de::Error::custom(format!(
26                "expected params sequence with length 1 but got {}",
27                seq.len()
28            )))
29        }
30        Ok(seq.remove(0))
31    }
32}
33
34/// A module that deserializes `[]` optionally
35pub mod empty_params {
36    use serde::{Deserialize, Deserializer};
37
38    pub fn deserialize<'de, D>(d: D) -> Result<(), D::Error>
39    where
40        D: Deserializer<'de>,
41    {
42        let seq = Option::<Vec<()>>::deserialize(d)?.unwrap_or_default();
43        if !seq.is_empty() {
44            return Err(serde::de::Error::custom(format!(
45                "expected params sequence with length 0 but got {}",
46                seq.len()
47            )))
48        }
49        Ok(())
50    }
51}
52
53/// A module that deserializes either a BlockNumberOrTag, or a simple number.
54pub mod lenient_block_number {
55    use alloy_rpc_types::BlockNumberOrTag;
56    use serde::{Deserialize, Deserializer};
57
58    /// Following the spec the block parameter is either:
59    ///
60    /// > HEX String - an integer block number
61    /// > String "earliest" for the earliest/genesis block
62    /// > String "latest" - for the latest mined block
63    /// > String "pending" - for the pending state/transactions
64    ///
65    /// and with EIP-1898:
66    /// > blockNumber: QUANTITY - a block number
67    /// > blockHash: DATA - a block hash
68    ///
69    /// <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1898.md>
70    ///
71    /// EIP-1898 does not all calls that use `BlockNumber` like `eth_getBlockByNumber` and doesn't
72    /// list raw integers as supported.
73    ///
74    /// However, there are dev node implementations that support integers, such as ganache: <https://github.com/foundry-rs/foundry/issues/1868>
75    ///
76    /// N.B.: geth does not support ints in `eth_getBlockByNumber`
77    pub fn lenient_block_number<'de, D>(deserializer: D) -> Result<BlockNumberOrTag, D::Error>
78    where
79        D: Deserializer<'de>,
80    {
81        LenientBlockNumber::deserialize(deserializer).map(Into::into)
82    }
83
84    /// Same as `lenient_block_number` but requires to be `[num; 1]`
85    pub fn lenient_block_number_seq<'de, D>(deserializer: D) -> Result<BlockNumberOrTag, D::Error>
86    where
87        D: Deserializer<'de>,
88    {
89        let num = <[LenientBlockNumber; 1]>::deserialize(deserializer)?[0].into();
90        Ok(num)
91    }
92
93    /// Various block number representations, See [`lenient_block_number()`]
94    #[derive(Clone, Copy, Deserialize)]
95    #[serde(untagged)]
96    pub enum LenientBlockNumber {
97        BlockNumber(BlockNumberOrTag),
98        Num(u64),
99    }
100
101    impl From<LenientBlockNumber> for BlockNumberOrTag {
102        fn from(b: LenientBlockNumber) -> Self {
103            match b {
104                LenientBlockNumber::BlockNumber(b) => b,
105                LenientBlockNumber::Num(b) => b.into(),
106            }
107        }
108    }
109}