helium_api/models/transactions/
payment_v2.rs

1use crate::models::{Hnt, Hst, Iot, Mobile};
2use serde::{Deserialize, Serialize};
3
4#[derive(Clone, Serialize, Deserialize, Debug)]
5pub struct PaymentV2 {
6    pub hash: String,
7    /// Fee is in datacredits
8    pub fee: u64,
9    pub nonce: u64,
10    pub payer: String,
11    pub payments: Vec<PaymentV2Payment>,
12}
13
14#[derive(Clone, Serialize, Debug)]
15#[serde(tag = "token_type", rename_all = "snake_case")]
16pub enum PaymentV2Payment {
17    Iot(IotPayment),
18    Hnt(HntPayment),
19    Hst(HstPayment),
20    Mobile(MobilePayment),
21}
22
23macro_rules! payment {
24    ($payment_type:ident, $token:ident) => {
25        #[derive(Clone, Serialize, Deserialize, Debug)]
26        pub struct $payment_type {
27            pub amount: $token,
28            pub memo: Option<String>,
29            pub payee: String,
30        }
31    };
32}
33payment!(HstPayment, Hst);
34payment!(IotPayment, Iot);
35payment!(HntPayment, Hnt);
36payment!(MobilePayment, Mobile);
37
38use serde::Deserializer;
39
40impl<'de> Deserialize<'de> for PaymentV2Payment {
41    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
42    where
43        D: Deserializer<'de>,
44    {
45        #[derive(Deserialize)]
46        #[serde(rename_all = "snake_case")]
47        enum Type {
48            Iot,
49            Hnt,
50            Hst,
51            Mobile,
52        }
53
54        #[derive(Deserialize)]
55        struct Inner {
56            pub token_type: Option<Type>,
57            pub amount: u64,
58            pub memo: Option<String>,
59            pub payee: String,
60        }
61
62        let i: Inner = Inner::deserialize(deserializer)?;
63
64        Ok(match i.token_type {
65            None => PaymentV2Payment::Hnt(HntPayment {
66                amount: Hnt::from(i.amount),
67                memo: i.memo,
68                payee: i.payee,
69            }),
70            Some(tag) => match tag {
71                Type::Iot => PaymentV2Payment::Iot(IotPayment {
72                    amount: Iot::from(i.amount),
73                    memo: i.memo,
74                    payee: i.payee,
75                }),
76                Type::Hnt => PaymentV2Payment::Hnt(HntPayment {
77                    amount: Hnt::from(i.amount),
78                    memo: i.memo,
79                    payee: i.payee,
80                }),
81                Type::Hst => PaymentV2Payment::Hst(HstPayment {
82                    amount: Hst::from(i.amount),
83                    memo: i.memo,
84                    payee: i.payee,
85                }),
86                Type::Mobile => PaymentV2Payment::Mobile(MobilePayment {
87                    amount: Mobile::from(i.amount),
88                    memo: i.memo,
89                    payee: i.payee,
90                }),
91            },
92        })
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use std::str::FromStr;
100
101    #[test]
102    fn deser_json_hst() {
103        let json_str = "\
104        {\
105            \"token_type\": \"hst\",\
106            \"payee\": \"1bdkwatM2APjn5cvo7eKiJGidoHAKJsHg8ReeguH49dtLacK6cR\",\
107            \"memo\": \"HNTAAAAAAAA=\",\
108            \"max\": false,\
109            \"amount\": 160000000\
110          }\
111        ";
112        let hnt_payment: PaymentV2Payment =
113            serde_json::from_str(json_str).expect("hst_payment deserialization");
114        if let PaymentV2Payment::Hst(hst) = hnt_payment {
115            assert_eq!(hst.amount, Hst::from_str("1.6").expect("HST"));
116        } else {
117            assert!(false)
118        }
119    }
120
121    #[test]
122    fn deser_json_hnt() {
123        // when no token_type is given, we default to HNT
124        let json_str = "\
125        {\
126            \"payee\": \"1bdkwatM2APjn5cvo7eKiJGidoHAKJsHg8ReeguH49dtLacK6cR\",\
127            \"memo\": \"HNTAAAAAAAA=\",\
128            \"max\": false,\
129            \"amount\": 160000000\
130          }\
131        ";
132        let hnt_payment: PaymentV2Payment =
133            serde_json::from_str(json_str).expect("hnt_payment deserialization");
134        if let PaymentV2Payment::Hnt(hnt) = hnt_payment {
135            assert_eq!(hnt.amount, Hnt::from_str("1.6").expect("HNT"));
136        } else {
137            assert!(false)
138        }
139    }
140}