waves_rust/model/asset/
balance.rs

1use crate::error::{Error, Result};
2use crate::model::{Address, AssetId, IssueTransactionInfo};
3use crate::util::JsonDeserializer;
4use serde_json::Value;
5
6#[derive(Clone, Eq, PartialEq, Debug)]
7pub struct AssetsBalanceResponse {
8    address: Address,
9    balances: Vec<AssetBalance>,
10}
11
12impl AssetsBalanceResponse {
13    pub fn new(address: Address, balances: Vec<AssetBalance>) -> AssetsBalanceResponse {
14        AssetsBalanceResponse { address, balances }
15    }
16
17    pub fn address(&self) -> Address {
18        self.address.clone()
19    }
20
21    pub fn balances(&self) -> Vec<AssetBalance> {
22        self.balances.clone()
23    }
24}
25
26impl TryFrom<&Value> for AssetsBalanceResponse {
27    type Error = Error;
28
29    fn try_from(value: &Value) -> Result<Self> {
30        let address = Address::from_string(&JsonDeserializer::safe_to_string_from_field(
31            value, "address",
32        )?)?;
33        let balances = JsonDeserializer::safe_to_array_from_field(value, "balances")?
34            .iter()
35            .map(|v| v.try_into())
36            .collect::<Result<Vec<AssetBalance>>>()?;
37        Ok(AssetsBalanceResponse::new(address, balances))
38    }
39}
40
41#[derive(Clone, Eq, PartialEq, Debug)]
42pub struct AssetBalance {
43    asset_id: AssetId,
44    balance: u64,
45    reissuable: bool,
46    min_sponsored_asset_fee: Option<u64>,
47    sponsor_balance: Option<u64>,
48    quantity: u64,
49    issue_transaction: Option<IssueTransactionInfo>,
50}
51
52impl AssetBalance {
53    pub fn new(
54        asset_id: AssetId,
55        balance: u64,
56        reissuable: bool,
57        min_sponsored_asset_fee: Option<u64>,
58        sponsor_balance: Option<u64>,
59        quantity: u64,
60        issue_transaction: Option<IssueTransactionInfo>,
61    ) -> AssetBalance {
62        AssetBalance {
63            asset_id,
64            balance,
65            reissuable,
66            min_sponsored_asset_fee,
67            sponsor_balance,
68            quantity,
69            issue_transaction,
70        }
71    }
72
73    pub fn asset_id(&self) -> AssetId {
74        self.asset_id.clone()
75    }
76
77    pub fn balance(&self) -> u64 {
78        self.balance
79    }
80
81    pub fn reissuable(&self) -> bool {
82        self.reissuable
83    }
84
85    pub fn min_sponsored_asset_fee(&self) -> Option<u64> {
86        self.min_sponsored_asset_fee
87    }
88
89    pub fn sponsor_balance(&self) -> Option<u64> {
90        self.sponsor_balance
91    }
92
93    pub fn quantity(&self) -> u64 {
94        self.quantity
95    }
96
97    pub fn issue_transaction(&self) -> Option<IssueTransactionInfo> {
98        self.issue_transaction.clone()
99    }
100}
101
102impl TryFrom<&Value> for AssetBalance {
103    type Error = Error;
104
105    fn try_from(value: &Value) -> Result<Self> {
106        let asset_id = AssetId::from_string(&JsonDeserializer::safe_to_string_from_field(
107            value, "assetId",
108        )?)?;
109        let balance = JsonDeserializer::safe_to_int_from_field(value, "balance")? as u64;
110        let reissuable = JsonDeserializer::safe_to_boolean_from_field(value, "reissuable")?;
111        let min_sponsored_asset_fee: Option<u64> = value["minSponsoredAssetFee"].as_u64();
112        let sponsor_balance: Option<u64> = value["sponsorBalance"].as_u64();
113        let quantity = JsonDeserializer::safe_to_int_from_field(value, "quantity")? as u64;
114        let issue_transaction = match value["issueTransaction"].as_object() {
115            Some(obj) => {
116                let issue_json: &Value = &obj.clone().into();
117                Some(issue_json.try_into()?)
118            }
119            None => None,
120        };
121        Ok(AssetBalance::new(
122            asset_id,
123            balance,
124            reissuable,
125            min_sponsored_asset_fee,
126            sponsor_balance,
127            quantity,
128            issue_transaction,
129        ))
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use crate::error::Result;
136    use crate::model::asset::balance::AssetsBalanceResponse;
137    use crate::model::ByteString;
138    use serde_json::Value;
139    use std::fs;
140
141    #[test]
142    fn test_json_to_assets_balance_response() -> Result<()> {
143        let data = fs::read_to_string("./tests/resources/assets/assets_balance_rs.json")
144            .expect("Unable to read file");
145        let json: &Value = &serde_json::from_str(&data).expect("failed to convert");
146        let assets_balance: AssetsBalanceResponse = json.try_into()?;
147        assert_eq!(
148            "3Mq3pueXcAgLcuWvJzJ4ndRHfqYgjUZvL7q",
149            assets_balance.address().encoded()
150        );
151
152        let balances = assets_balance.balances();
153        let asset_balance1 = &balances[0];
154        assert_eq!(
155            "85gPhjumNgwaMUpGfx9jEQqJMorbEjTQ4EUAHwfoYKjd",
156            asset_balance1.asset_id().encoded()
157        );
158        assert_eq!(false, asset_balance1.reissuable());
159        assert_eq!(None, asset_balance1.min_sponsored_asset_fee());
160        assert_eq!(None, asset_balance1.sponsor_balance());
161        assert_eq!(32, asset_balance1.quantity());
162        assert_eq!(42, asset_balance1.balance());
163        let issue_tx = asset_balance1
164            .issue_transaction()
165            .expect("must not be empty");
166
167        assert_eq!(
168            "85gPhjumNgwaMUpGfx9jEQqJMorbEjTQ4EUAHwfoYKjd",
169            issue_tx.asset_id().encoded()
170        );
171        assert_eq!("test asset", issue_tx.name());
172        assert_eq!(32, issue_tx.quantity());
173        assert_eq!(false, issue_tx.is_reissuable());
174        assert_eq!(3, issue_tx.decimals());
175        assert_eq!("this is test asset", issue_tx.description());
176        assert_eq!(None, issue_tx.script());
177
178        let asset_balance2 = &assets_balance.balances()[1];
179        assert_eq!(
180            "GyH2wqKQcjHtz6KgkUNzUpDYYy1azqZdYHZ2awXHWqYx",
181            asset_balance2.asset_id().encoded()
182        );
183        assert_eq!(false, asset_balance2.reissuable());
184        assert_eq!(Some(1), asset_balance2.min_sponsored_asset_fee());
185        assert_eq!(Some(199900003), asset_balance2.sponsor_balance());
186        assert_eq!(2, asset_balance2.quantity());
187        assert_eq!(None, asset_balance2.issue_transaction());
188        assert_eq!(2, asset_balance2.balance());
189
190        Ok(())
191    }
192}