sui_jsonrpc/
serde.rs

1use std::fmt::Display;
2use std::str::FromStr;
3
4use af_sui_types::GasCostSummary;
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use serde_with::{DeserializeAs, DisplayFromStr, SerializeAs, serde_as};
7
8// =============================================================================
9//  BigInt
10// =============================================================================
11
12#[serde_as]
13#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy)]
14pub struct BigInt<T>(#[serde_as(as = "serde_with::DisplayFromStr")] T)
15where
16    T: Display + FromStr,
17    <T as FromStr>::Err: Display;
18
19impl<T> BigInt<T>
20where
21    T: Display + FromStr,
22    <T as FromStr>::Err: Display,
23{
24    pub fn into_inner(self) -> T {
25        self.0
26    }
27}
28
29impl<T> SerializeAs<T> for BigInt<T>
30where
31    T: Display + FromStr + Copy,
32    <T as FromStr>::Err: Display,
33{
34    fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
35    where
36        S: Serializer,
37    {
38        Self(*value).serialize(serializer)
39    }
40}
41
42impl<'de, T> DeserializeAs<'de, T> for BigInt<T>
43where
44    T: Display + FromStr + Copy,
45    <T as FromStr>::Err: Display,
46{
47    fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
48    where
49        D: Deserializer<'de>,
50    {
51        Ok(*Self::deserialize(deserializer)?)
52    }
53}
54
55impl<T> From<T> for BigInt<T>
56where
57    T: Display + FromStr,
58    <T as FromStr>::Err: Display,
59{
60    fn from(v: T) -> Self {
61        Self(v)
62    }
63}
64
65impl<T> std::ops::Deref for BigInt<T>
66where
67    T: Display + FromStr,
68    <T as FromStr>::Err: Display,
69{
70    type Target = T;
71
72    fn deref(&self) -> &Self::Target {
73        &self.0
74    }
75}
76
77impl<T> Display for BigInt<T>
78where
79    T: Display + FromStr,
80    <T as FromStr>::Err: Display,
81{
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(f, "{}", self.0)
84    }
85}
86
87// =============================================================================
88//  Base64orBase58
89// =============================================================================
90
91/// Always serialize as base64, but deserialize from either Base64 or Base58
92pub(crate) struct Base64orBase58;
93
94impl<T> SerializeAs<T> for Base64orBase58
95where
96    T: AsRef<[u8]>,
97{
98    fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
99    where
100        S: Serializer,
101    {
102        let encoded_string = af_sui_types::encode_base64_default(value);
103        encoded_string.serialize(serializer)
104    }
105}
106
107impl<'de> DeserializeAs<'de, Vec<u8>> for Base64orBase58 {
108    fn deserialize_as<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
109    where
110        D: Deserializer<'de>,
111    {
112        let s = String::deserialize(deserializer)?;
113
114        af_sui_types::decode_base64_default(&s)
115            .or_else(|_| af_sui_types::encoding::Base58::decode(&s))
116            .map_err(|_| serde::de::Error::custom("Deserialization failed"))
117    }
118}
119
120#[serde_as]
121#[derive(Serialize, Deserialize)]
122#[serde(rename_all = "camelCase")]
123pub(crate) struct GasCostSummaryJson {
124    #[serde_as(as = "DisplayFromStr")]
125    computation_cost: u64,
126    #[serde_as(as = "DisplayFromStr")]
127    storage_cost: u64,
128    #[serde_as(as = "DisplayFromStr")]
129    storage_rebate: u64,
130    #[serde_as(as = "DisplayFromStr")]
131    non_refundable_storage_fee: u64,
132}
133
134impl From<GasCostSummaryJson> for GasCostSummary {
135    fn from(
136        GasCostSummaryJson {
137            computation_cost,
138            storage_cost,
139            storage_rebate,
140            non_refundable_storage_fee,
141        }: GasCostSummaryJson,
142    ) -> Self {
143        Self {
144            computation_cost,
145            storage_cost,
146            storage_rebate,
147            non_refundable_storage_fee,
148        }
149    }
150}
151
152impl From<GasCostSummary> for GasCostSummaryJson {
153    fn from(
154        GasCostSummary {
155            computation_cost,
156            storage_cost,
157            storage_rebate,
158            non_refundable_storage_fee,
159        }: GasCostSummary,
160    ) -> Self {
161        Self {
162            computation_cost,
163            storage_cost,
164            storage_rebate,
165            non_refundable_storage_fee,
166        }
167    }
168}
169
170#[cfg(test)]
171mod test {
172    use super::*;
173
174    #[serde_as]
175    #[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
176    #[serde(rename_all = "camelCase")]
177    struct Bcs {
178        #[serde_as(as = "Base64orBase58")]
179        bcs: Vec<u8>,
180    }
181
182    #[test]
183    fn new_bcs_format() {
184        let bytes = vec![0, 1, 2, 3, 4];
185        let untagged_base58 = r#"{"bcs":"12VfUX"}"#;
186        let tagged_base58 = r#"{"bcsEncoding":"base58","bcs":"12VfUX"}"#;
187        let tagged_base64 = r#"{"bcsEncoding":"base64","bcs":"AAECAwQ="}"#;
188
189        println!(
190            "{}",
191            serde_json::to_string(&Bcs { bcs: bytes.clone() }).unwrap()
192        );
193
194        assert_eq!(
195            bytes,
196            serde_json::from_str::<Bcs>(untagged_base58).unwrap().bcs
197        );
198        assert_eq!(
199            bytes,
200            serde_json::from_str::<Bcs>(tagged_base58).unwrap().bcs
201        );
202        assert_eq!(
203            bytes,
204            serde_json::from_str::<Bcs>(tagged_base64).unwrap().bcs
205        );
206
207        // Roundtrip base64
208        let name = serde_json::from_str::<Bcs>(tagged_base64).unwrap();
209        let json = serde_json::to_string(&name).unwrap();
210        let from_json = serde_json::from_str::<Bcs>(&json).unwrap();
211        assert_eq!(name, from_json);
212
213        // Roundtrip base58
214        let name = serde_json::from_str::<Bcs>(tagged_base58).unwrap();
215        let json = serde_json::to_string(&name).unwrap();
216        let from_json = serde_json::from_str::<Bcs>(&json).unwrap();
217        assert_eq!(name, from_json);
218    }
219}