cml_chain_wasm/assets/
utils.rs

1use std::{
2    convert::{TryFrom, TryInto},
3    ops::Deref,
4};
5
6use crate::{assets::AssetName, AssetNameList, MapAssetNameToNonZeroInt64, PolicyId, PolicyIdList};
7use wasm_bindgen::{prelude::wasm_bindgen, JsError};
8
9use cml_core_wasm::{
10    impl_raw_bytes_api, impl_wasm_cbor_json_api, impl_wasm_conversions, impl_wasm_map,
11};
12
13use super::Coin;
14
15impl_wasm_map!(
16    cml_chain::assets::AssetName,
17    Coin,
18    AssetName,
19    Coin,
20    AssetNameList,
21    MapAssetNameToCoin,
22    false,
23    true,
24    false,
25    true
26);
27
28#[wasm_bindgen]
29impl AssetName {
30    /**
31     * Create an AssetName from utf8 string. 64 byte (not char!) maximum.
32     */
33    #[allow(clippy::should_implement_trait)]
34    pub fn from_str(utf8_str: &str) -> Result<AssetName, JsError> {
35        cml_chain::assets::AssetName::try_from(utf8_str)
36            .map(Into::into)
37            .map_err(Into::into)
38    }
39
40    /**
41     * AssetName as a utf8 string if it's possible. Will error if the asset is not utf8
42     */
43    pub fn to_str(&self) -> Result<String, JsError> {
44        self.as_ref()
45            .try_into()
46            .map(str::to_owned)
47            .map_err(Into::into)
48    }
49}
50
51impl_raw_bytes_api!(cml_chain::assets::AssetName, AssetName);
52
53#[derive(Clone, Debug)]
54#[wasm_bindgen]
55pub struct MultiAsset(cml_chain::assets::MultiAsset);
56
57#[wasm_bindgen]
58impl MultiAsset {
59    pub fn new() -> Self {
60        Self(cml_chain::assets::MultiAsset::default())
61    }
62
63    pub fn policy_count(&self) -> usize {
64        self.0.len()
65    }
66
67    pub fn insert_assets(
68        &mut self,
69        policy_id: &PolicyId,
70        assets: &MapAssetNameToCoin,
71    ) -> Option<MapAssetNameToCoin> {
72        self.0
73            .insert(policy_id.clone().into(), assets.clone().into())
74            .map(Into::into)
75    }
76
77    pub fn get_assets(&self, key: &PolicyId) -> Option<MapAssetNameToCoin> {
78        self.0.deref().get(key.as_ref()).map(|v| v.clone().into())
79    }
80
81    /// Get the value of policy_id:asset_name if it exists.
82    pub fn get(&self, policy_id: &PolicyId, asset: &AssetName) -> Option<Coin> {
83        self.0.get(policy_id.as_ref(), asset.as_ref())
84    }
85
86    /// Set the value of policy_id:asset_name to value.
87    /// Returns the previous value, or None if it didn't exist
88    pub fn set(&mut self, policy_id: &PolicyId, asset: &AssetName, value: Coin) -> Option<Coin> {
89        self.0
90            .set(policy_id.clone().into(), asset.clone().into(), value)
91    }
92
93    pub fn keys(&self) -> PolicyIdList {
94        PolicyIdList(self.0.iter().map(|(k, _v)| *k).collect::<Vec<_>>())
95    }
96
97    /// Adds to multiassets together, checking value bounds.
98    /// Does not modify self, and instead returns the result.
99    pub fn checked_add(&self, rhs: &MultiAsset) -> Result<MultiAsset, JsError> {
100        self.0
101            .checked_add(rhs.as_ref())
102            .map(Into::into)
103            .map_err(Into::into)
104    }
105
106    /// Subtracts rhs from this multiasset.
107    /// This does not modify self, and instead returns the result.
108    /// If this would cause there to be fewer than 0 of a given asset
109    /// an error will be returned.
110    /// Use clamped_sub if you need to only try to remove assets when they exist
111    /// and ignore them when they don't.
112    pub fn checked_sub(&self, rhs: &MultiAsset) -> Result<MultiAsset, JsError> {
113        self.0
114            .checked_sub(rhs.as_ref())
115            .map(Into::into)
116            .map_err(Into::into)
117    }
118
119    /// Sybtracts rhs from this multiasset.
120    /// If this would cause there to be 0 or fewer of a given asset
121    /// it will simply be removed entirely from the result.
122    pub fn clamped_sub(&self, rhs: &MultiAsset) -> Self {
123        use cml_chain::assets::ClampedSub;
124        self.0.clamped_sub(rhs.as_ref()).into()
125    }
126}
127
128impl_wasm_conversions!(cml_chain::assets::MultiAsset, MultiAsset);
129
130#[derive(Clone, Debug)]
131#[wasm_bindgen]
132pub struct Mint(cml_chain::assets::Mint);
133
134#[wasm_bindgen]
135impl Mint {
136    pub fn new() -> Self {
137        Self(cml_chain::assets::Mint::default())
138    }
139
140    pub fn policy_count(&self) -> usize {
141        self.0.len()
142    }
143
144    pub fn insert_assets(
145        &mut self,
146        policy_id: &PolicyId,
147        assets: &MapAssetNameToNonZeroInt64,
148    ) -> Option<MapAssetNameToNonZeroInt64> {
149        self.0
150            .insert(policy_id.clone().into(), assets.clone().into())
151            .map(Into::into)
152    }
153
154    pub fn get_assets(&self, key: &PolicyId) -> Option<MapAssetNameToNonZeroInt64> {
155        self.0.deref().get(key.as_ref()).map(|v| v.clone().into())
156    }
157
158    /// Get the value of policy_id:asset_name if it exists.
159    pub fn get(&self, policy_id: &PolicyId, asset: &AssetName) -> Option<i64> {
160        self.0.get(policy_id.as_ref(), asset.as_ref())
161    }
162
163    /// Set the value of policy_id:asset_name to value.
164    /// Returns the previous value, or None if it didn't exist
165    pub fn set(&mut self, policy_id: &PolicyId, asset: &AssetName, value: i64) -> Option<i64> {
166        self.0
167            .set(policy_id.clone().into(), asset.clone().into(), value)
168    }
169
170    pub fn keys(&self) -> PolicyIdList {
171        PolicyIdList(self.0.iter().map(|(k, _v)| *k).collect::<Vec<_>>())
172    }
173
174    /// Adds two mints together, checking value bounds.
175    /// Does not modify self, and instead returns the result.
176    pub fn checked_add(&self, rhs: &Mint) -> Result<Mint, JsError> {
177        self.0
178            .checked_add(rhs.as_ref())
179            .map(Into::into)
180            .map_err(Into::into)
181    }
182
183    /// Subtracts rhs from this mint.
184    /// This does not modify self, and instead returns the result.
185    pub fn checked_sub(&self, rhs: &Mint) -> Result<Mint, JsError> {
186        self.0
187            .checked_sub(rhs.as_ref())
188            .map(Into::into)
189            .map_err(Into::into)
190    }
191
192    /// Returns the multiasset where only positive (minting) entries are present
193    pub fn as_positive_multiasset(&self) -> MultiAsset {
194        self.0.as_positive_multiasset().into()
195    }
196
197    /// Returns the multiasset where only negative (burning) entries are present
198    pub fn as_negative_multiasset(&self) -> MultiAsset {
199        self.0.as_negative_multiasset().into()
200    }
201}
202
203impl_wasm_conversions!(cml_chain::assets::Mint, Mint);
204
205#[wasm_bindgen]
206#[derive(Debug, Clone)]
207pub struct Value(cml_chain::assets::Value);
208
209impl_wasm_cbor_json_api!(Value);
210
211#[wasm_bindgen]
212impl Value {
213    pub fn from_coin(coin: Coin) -> Self {
214        cml_chain::assets::Value::from(coin).into()
215    }
216
217    pub fn new(coin: Coin, multiasset: &MultiAsset) -> Self {
218        cml_chain::assets::Value::new(coin, multiasset.clone().into()).into()
219    }
220
221    pub fn coin(&self) -> Coin {
222        self.0.coin
223    }
224
225    pub fn multi_asset(&self) -> MultiAsset {
226        self.0.multiasset.clone().into()
227    }
228
229    pub fn zero() -> Value {
230        cml_chain::assets::Value::zero().into()
231    }
232
233    pub fn is_zero(&self) -> bool {
234        self.0.is_zero()
235    }
236
237    pub fn has_multiassets(&self) -> bool {
238        self.0.has_multiassets()
239    }
240
241    pub fn checked_add(&self, rhs: &Value) -> Result<Value, JsError> {
242        self.0
243            .checked_add(rhs.as_ref())
244            .map(Into::into)
245            .map_err(Into::into)
246    }
247
248    /// Subtract ADA and/or assets
249    /// Removes an asset from the list if the result is 0 or less
250    /// Does not modify this object, instead the result is returned
251    /// None is returned if there would be integer underflow
252    pub fn checked_sub(&self, rhs: &Value) -> Result<Value, JsError> {
253        self.0
254            .checked_sub(rhs.as_ref())
255            .map(Into::into)
256            .map_err(Into::into)
257    }
258
259    pub fn clamped_sub(&self, rhs: &Value) -> Value {
260        self.0.clamped_sub(rhs.as_ref()).into()
261    }
262}
263
264impl_wasm_conversions!(cml_chain::assets::Value, Value);