Skip to content

Commit e19c261

Browse files
committed
Reworked total-input calculation to process negative mint values
1 parent efc5e37 commit e19c261

File tree

3 files changed

+133
-36
lines changed

3 files changed

+133
-36
lines changed

rust/src/lib.rs

Lines changed: 103 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2691,27 +2691,35 @@ impl Mint {
26912691
ScriptHashes(self.0.iter().map(|(k, _v)| k.clone()).collect::<Vec<ScriptHash>>())
26922692
}
26932693

2694-
pub fn to_multiasset(&self) -> Result<MultiAsset, JsError> {
2695-
self.0.iter().fold(Ok(MultiAsset::new()), | res, e | {
2696-
let assets: Result<Assets, JsError> = (e.1).0.iter().fold(Ok(Assets::new()), | res, e| {
2697-
let mut assets = res?;
2698-
if e.1.is_positive() {
2699-
assets.insert(e.0, &e.1.as_positive().unwrap());
2700-
Ok(assets)
2701-
} else {
2702-
Err(JsError::from_str("Asset amount cannot be negative!"))
2694+
fn as_multiasset(&self, is_positive: bool) -> MultiAsset {
2695+
self.0.iter().fold(MultiAsset::new(), | res, e | {
2696+
let assets: Assets = (e.1).0.iter().fold(Assets::new(), | res, e| {
2697+
let mut assets = res;
2698+
if e.1.is_positive() == is_positive {
2699+
let amount = match is_positive {
2700+
true => e.1.as_positive(),
2701+
false => e.1.as_negative(),
2702+
};
2703+
assets.insert(e.0, &amount.unwrap());
27032704
}
2705+
assets
27042706
});
2705-
let mut ma = res?;
2706-
ma.insert(e.0, &assets?);
2707-
Ok(ma)
2707+
let mut ma = res;
2708+
if !assets.0.is_empty() {
2709+
ma.insert(e.0, &assets);
2710+
}
2711+
ma
27082712
})
27092713
}
27102714

2711-
pub fn to_value(&self) -> Result<Value, JsError> {
2712-
let mut val = Value::new(&Coin::zero());
2713-
val.set_multiasset(&self.to_multiasset()?);
2714-
Ok(val)
2715+
/// Returns the multiasset where only positive (minting) entries are present
2716+
pub fn as_positive_multiasset(&self) -> MultiAsset {
2717+
self.as_multiasset(true)
2718+
}
2719+
2720+
/// Returns the multiasset where only negative (burning) entries are present
2721+
pub fn as_negative_multiasset(&self) -> MultiAsset {
2722+
self.as_multiasset(false)
27152723
}
27162724
}
27172725

@@ -2799,7 +2807,7 @@ mod tests {
27992807
}
28002808

28012809
#[test]
2802-
fn mint_to_value() {
2810+
fn mint_to_multiasset() {
28032811
let policy_id1 = PolicyID::from([0u8; 28]);
28042812
let policy_id2 = PolicyID::from([1u8; 28]);
28052813
let name1 = AssetName::new(vec![0u8, 1, 2, 3]).unwrap();
@@ -2819,12 +2827,7 @@ mod tests {
28192827
mint.insert(&policy_id1, &mass1);
28202828
mint.insert(&policy_id2, &mass2);
28212829

2822-
let val = mint.to_value().unwrap();
2823-
2824-
assert_eq!(val.coin(), Coin::zero());
2825-
assert!(val.multiasset().is_some());
2826-
2827-
let multiasset = val.multiasset().unwrap();
2830+
let multiasset = mint.as_positive_multiasset();
28282831
assert_eq!(multiasset.len(), 2);
28292832

28302833
let ass1 = multiasset.get(&policy_id1).unwrap();
@@ -2841,22 +2844,93 @@ mod tests {
28412844
}
28422845

28432846
#[test]
2844-
fn mint_to_value_negative_err() {
2847+
fn mint_to_negative_multiasset() {
28452848
let policy_id1 = PolicyID::from([0u8; 28]);
2849+
let policy_id2 = PolicyID::from([1u8; 28]);
28462850
let name1 = AssetName::new(vec![0u8, 1, 2, 3]).unwrap();
2851+
let name2 = AssetName::new(vec![0u8, 4, 5, 6]).unwrap();
2852+
let amount1 = BigNum::from_str("1234").unwrap();
2853+
let amount2 = BigNum::from_str("5678").unwrap();
28472854

28482855
let mut mass1 = MintAssets::new();
2849-
mass1.insert(&name1, Int::new_i32(-42));
2856+
mass1.insert(&name1, Int::new(&amount1));
2857+
mass1.insert(&name2, Int::new_negative(&amount2));
2858+
2859+
let mut mass2 = MintAssets::new();
2860+
mass2.insert(&name1, Int::new_negative(&amount1));
2861+
mass2.insert(&name2, Int::new(&amount2));
28502862

28512863
let mut mint = Mint::new();
28522864
mint.insert(&policy_id1, &mass1);
2865+
mint.insert(&policy_id2, &mass2);
2866+
2867+
let p_multiasset = mint.as_positive_multiasset();
2868+
let n_multiasset = mint.as_negative_multiasset();
2869+
2870+
assert_eq!(p_multiasset.len(), 2);
2871+
assert_eq!(n_multiasset.len(), 2);
2872+
2873+
let p_ass1 = p_multiasset.get(&policy_id1).unwrap();
2874+
let p_ass2 = p_multiasset.get(&policy_id2).unwrap();
2875+
2876+
let n_ass1 = n_multiasset.get(&policy_id1).unwrap();
2877+
let n_ass2 = n_multiasset.get(&policy_id2).unwrap();
2878+
2879+
assert_eq!(p_ass1.len(), 1);
2880+
assert_eq!(p_ass2.len(), 1);
2881+
assert_eq!(n_ass1.len(), 1);
2882+
assert_eq!(n_ass2.len(), 1);
2883+
2884+
assert_eq!(p_ass1.get(&name1).unwrap(), amount1);
2885+
assert!(p_ass1.get(&name2).is_none());
2886+
2887+
assert!(p_ass2.get(&name1).is_none());
2888+
assert_eq!(p_ass2.get(&name2).unwrap(), amount2);
2889+
2890+
assert!(n_ass1.get(&name1).is_none());
2891+
assert_eq!(n_ass1.get(&name2).unwrap(), amount2);
2892+
2893+
assert_eq!(n_ass2.get(&name1).unwrap(), amount1);
2894+
assert!(n_ass2.get(&name2).is_none());
2895+
}
2896+
2897+
#[test]
2898+
fn mint_to_negative_multiasset_empty() {
2899+
let policy_id1 = PolicyID::from([0u8; 28]);
2900+
let name1 = AssetName::new(vec![0u8, 1, 2, 3]).unwrap();
2901+
let amount1 = BigNum::from_str("1234").unwrap();
2902+
2903+
let mut mass1 = MintAssets::new();
2904+
mass1.insert(&name1, Int::new(&amount1));
2905+
2906+
let mut mass2 = MintAssets::new();
2907+
mass2.insert(&name1, Int::new_negative(&amount1));
2908+
2909+
let mut mint1 = Mint::new();
2910+
mint1.insert(&policy_id1, &mass1);
2911+
2912+
let mut mint2 = Mint::new();
2913+
mint2.insert(&policy_id1, &mass2);
2914+
2915+
let p_multiasset_some = mint1.as_positive_multiasset();
2916+
let p_multiasset_none = mint2.as_positive_multiasset();
2917+
2918+
let n_multiasset_none = mint1.as_negative_multiasset();
2919+
let n_multiasset_some = mint2.as_negative_multiasset();
2920+
2921+
assert_eq!(p_multiasset_some.len(), 1);
2922+
assert_eq!(p_multiasset_none.len(), 0);
28532923

2854-
let res = mint.to_value();
2924+
assert_eq!(n_multiasset_some.len(), 1);
2925+
assert_eq!(n_multiasset_none.len(), 0);
28552926

2856-
assert!(res.is_err());
2927+
let p_ass = p_multiasset_some.get(&policy_id1).unwrap();
2928+
let n_ass = n_multiasset_some.get(&policy_id1).unwrap();
28572929

2858-
let err = res.err().unwrap();
2930+
assert_eq!(p_ass.len(), 1);
2931+
assert_eq!(n_ass.len(), 1);
28592932

2860-
assert!(err.to_string().contains("cannot be negative"))
2933+
assert_eq!(p_ass.get(&name1).unwrap(), amount1);
2934+
assert_eq!(n_ass.get(&name1).unwrap(), amount1);
28612935
}
28622936
}

rust/src/tx_builder.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::*;
22
use super::fees;
33
use super::utils;
44
use std::collections::{BTreeMap, BTreeSet};
5+
use itertools::Itertools;
56

67
// comes from witsVKeyNeeded in the Ledger spec
78
fn witness_keys_for_cert(cert_enum: &Certificate, keys: &mut BTreeSet<Ed25519KeyHash>) {
@@ -580,11 +581,14 @@ impl TransactionBuilder {
580581
address: &Address,
581582
output_coin: &Coin,
582583
) -> Result<(), JsError> {
584+
if !amount.is_positive() {
585+
return Err(JsError::from_str("Output value must be positive!"));
586+
}
583587
self.add_mint_asset(policy_id, asset_name, amount.clone());
584588
let mut multiasset = Mint::new_from_entry(
585589
policy_id,
586590
&MintAssets::new_from_entry(asset_name, amount.clone())
587-
).to_multiasset()?;
591+
).as_positive_multiasset();
588592
self.add_output_coin_and_asset(address, output_coin, &multiasset)
589593
}
590594

@@ -600,11 +604,14 @@ impl TransactionBuilder {
600604
amount: Int,
601605
address: &Address,
602606
) -> Result<(), JsError> {
607+
if !amount.is_positive() {
608+
return Err(JsError::from_str("Output value must be positive!"));
609+
}
603610
self.add_mint_asset(policy_id, asset_name, amount.clone());
604611
let mut multiasset = Mint::new_from_entry(
605612
policy_id,
606613
&MintAssets::new_from_entry(asset_name, amount.clone())
607-
).to_multiasset()?;
614+
).as_positive_multiasset();
608615
self.add_output_asset_and_min_required_coin(address, &multiasset)
609616
}
610617

@@ -667,15 +674,20 @@ impl TransactionBuilder {
667674
)
668675
}
669676

670-
/// mint as value
671-
pub fn get_mint_value(&self) -> Result<Value, JsError> {
672-
self.mint.as_ref().map(|m| { m.to_value() }).unwrap_or(Ok(Value::zero()))
677+
/// Returns mint as tuple of (mint_value, burn_value) or two zero values
678+
fn get_mint_as_values(&self) -> (Value, Value) {
679+
self.mint.as_ref().map(|m| {
680+
(Value::new_from_assets(&m.as_positive_multiasset()),
681+
Value::new_from_assets(&m.as_negative_multiasset()))
682+
}).unwrap_or((Value::zero(), Value::zero()))
673683
}
674684

675685
fn get_total_input(&self) -> Result<Value, JsError> {
686+
let (mint_value, burn_value) = self.get_mint_as_values();
676687
self.get_explicit_input()?
677688
.checked_add(&self.get_implicit_input()?)?
678-
.checked_add(&self.get_mint_value()?)
689+
.checked_add(&mint_value)?
690+
.checked_sub(&burn_value)
679691
}
680692

681693
/// does not include fee

rust/src/utils.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,15 +265,26 @@ to_from_bytes!(Value);
265265

266266
#[wasm_bindgen]
267267
impl Value {
268+
268269
pub fn new(coin: &Coin) -> Value {
269270
Self {
270271
coin: coin.clone(),
271272
multiasset: None,
272273
}
273274
}
274275

276+
pub fn new_from_assets(multiasset: &MultiAsset) -> Value {
277+
match multiasset.0.is_empty() {
278+
true => Value::zero(),
279+
false => Self {
280+
coin: Coin::zero(),
281+
multiasset: Some(multiasset.clone()),
282+
}
283+
}
284+
}
285+
275286
pub fn zero() -> Value {
276-
Value::new(&to_bignum(0))
287+
Value::new(&Coin::zero())
277288
}
278289

279290
pub fn is_zero(&self) -> bool {

0 commit comments

Comments
 (0)