recall_ipc_api/
lib.rs

1// Copyright 2022-2024 Protocol Labs
2// SPDX-License-Identifier: MIT
3use ethers::utils::hex;
4use fvm_shared::{address::Address, econ::TokenAmount};
5use recall_ipc_types::EthAddress;
6use serde::de::Error as SerdeError;
7use serde::{Deserialize, Serialize, Serializer};
8use std::str::FromStr;
9
10pub mod address;
11pub mod checkpoint;
12pub mod cross;
13pub mod error;
14pub mod gateway;
15#[cfg(feature = "fil-actor")]
16mod runtime;
17pub mod subnet;
18pub mod subnet_id;
19pub mod validator;
20
21pub mod evm;
22pub mod merkle;
23pub mod staking;
24
25/// Converts an ethers::U256 TokenAmount into a FIL amount.
26pub fn eth_to_fil_amount(amount: &ethers::types::U256) -> anyhow::Result<TokenAmount> {
27    let v = fvm_shared::bigint::BigInt::from_str(&amount.to_string())?;
28    Ok(TokenAmount::from_atto(v))
29}
30
31pub fn ethers_address_to_fil_address(addr: &ethers::types::Address) -> anyhow::Result<Address> {
32    let raw_addr = format!("{addr:?}");
33    log::debug!("raw evm subnet addr: {raw_addr:}");
34
35    let eth_addr = EthAddress::from_str(&raw_addr)?;
36    Ok(Address::from(eth_addr))
37}
38
39/// Marker type for serialising data to/from string
40pub struct HumanReadable;
41
42#[macro_export]
43macro_rules! serialise_human_readable_str {
44    ($typ:ty) => {
45        impl serde_with::SerializeAs<$typ> for $crate::HumanReadable {
46            fn serialize_as<S>(value: &$typ, serializer: S) -> Result<S::Ok, S::Error>
47            where
48                S: serde::Serializer,
49            {
50                if serializer.is_human_readable() {
51                    value.to_string().serialize(serializer)
52                } else {
53                    value.serialize(serializer)
54                }
55            }
56        }
57    };
58}
59
60#[macro_export]
61macro_rules! deserialize_human_readable_str {
62    ($typ:ty) => {
63        use serde::de::Error as DeserializeError;
64        use serde::{Deserialize, Serialize};
65
66        impl<'de> serde_with::DeserializeAs<'de, $typ> for $crate::HumanReadable {
67            fn deserialize_as<D>(deserializer: D) -> Result<$typ, D::Error>
68            where
69                D: serde::de::Deserializer<'de>,
70            {
71                if deserializer.is_human_readable() {
72                    let s = String::deserialize(deserializer)?;
73                    <$typ>::from_str(&s).map_err(|_| {
74                        D::Error::custom(format!(
75                            "cannot parse from str {}",
76                            core::any::type_name::<$typ>()
77                        ))
78                    })
79                } else {
80                    <$typ>::deserialize(deserializer)
81                }
82            }
83        }
84    };
85}
86
87#[macro_export]
88macro_rules! as_human_readable_str {
89    ($typ:ty) => {
90        $crate::serialise_human_readable_str!($typ);
91        $crate::deserialize_human_readable_str!($typ);
92    };
93}
94
95impl serde_with::SerializeAs<Vec<u8>> for HumanReadable {
96    fn serialize_as<S>(source: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
97    where
98        S: Serializer,
99    {
100        if serializer.is_human_readable() {
101            hex::encode(source).serialize(serializer)
102        } else {
103            source.serialize(serializer)
104        }
105    }
106}
107
108impl<'de> serde_with::DeserializeAs<'de, Vec<u8>> for HumanReadable {
109    fn deserialize_as<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
110    where
111        D: serde::de::Deserializer<'de>,
112    {
113        if deserializer.is_human_readable() {
114            let s = String::deserialize(deserializer)?;
115            Ok(hex::decode(s)
116                .map_err(|e| D::Error::custom(format!("cannot parse from str {e}")))?)
117        } else {
118            Vec::<u8>::deserialize(deserializer)
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use crate::HumanReadable;
126    use serde::{Deserialize, Serialize};
127    use serde_with::serde_as;
128
129    #[test]
130    fn test_human_readable() {
131        #[serde_as]
132        #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
133        struct T {
134            #[serde_as(as = "HumanReadable")]
135            bytes: Vec<u8>,
136        }
137
138        let t = T {
139            bytes: vec![1, 2, 3, 4],
140        };
141
142        let serialized_t = serde_json::to_vec(&t).unwrap();
143        let dserialized_t = serde_json::from_slice(&serialized_t).unwrap();
144        assert_eq!(t, dserialized_t);
145
146        let serialized_t = fvm_ipld_encoding::to_vec(&t).unwrap();
147        let dserialized_t = fvm_ipld_encoding::from_slice(&serialized_t).unwrap();
148        assert_eq!(t, dserialized_t);
149    }
150}