whisky_pallas/wrapper/transaction_body/
value.rs1use pallas::{
2 codec::utils::PositiveCoin,
3 ledger::primitives::{conway::Value as PallasValue, Fragment},
4};
5
6use crate::wrapper::transaction_body::MultiassetPositiveCoin;
7use whisky_common::WError;
8
9#[derive(Debug, PartialEq, Clone)]
10pub struct Value {
11 pub inner: PallasValue,
12}
13
14impl Value {
15 pub fn new(coin: u64, multiasset: Option<MultiassetPositiveCoin>) -> Self {
16 match multiasset {
17 Some(ma) => Self {
18 inner: PallasValue::Multiasset(coin, ma.inner),
19 },
20 None => Self {
21 inner: PallasValue::Coin(coin),
22 },
23 }
24 }
25
26 pub fn add(&self, other: &Value) -> Result<Value, WError> {
27 match (&self.inner, &other.inner) {
28 (PallasValue::Coin(a), PallasValue::Coin(b)) => Ok(Value {
29 inner: PallasValue::Coin(a + b),
30 }),
31 (PallasValue::Coin(a), PallasValue::Multiasset(b, b_ma)) => Ok(Value {
32 inner: PallasValue::Multiasset(a + b, b_ma.clone()),
33 }),
34 (PallasValue::Multiasset(a, a_ma), PallasValue::Coin(b)) => Ok(Value {
35 inner: PallasValue::Multiasset(a + b, a_ma.clone()),
36 }),
37 (PallasValue::Multiasset(a, a_ma), PallasValue::Multiasset(b, b_ma)) => {
38 let mut combined_ma = a_ma.clone();
39 for (policy_id, assets) in b_ma.iter() {
40 let entry = combined_ma.entry(*policy_id).or_default();
41 for (asset_name, amount) in assets.iter() {
42 let asset_entry = entry.entry(asset_name.clone());
43 match asset_entry {
44 std::collections::btree_map::Entry::Vacant(_vacant_entry) => {
45 entry.insert(asset_name.clone(), *amount);
46 }
47 std::collections::btree_map::Entry::Occupied(occupied_entry) => {
48 let new_amount =
49 u64::from(*occupied_entry.get()) + u64::from(amount);
50 *occupied_entry.into_mut() = PositiveCoin::try_from(new_amount)
51 .map_err(|_| {
52 WError::new(
53 "Value - Add:",
54 "Failed to create PositiveCoin from added asset amounts",
55 )
56 })?;
57 }
58 }
59 }
60 }
61 Ok(Value {
62 inner: PallasValue::Multiasset(a + b, combined_ma),
63 })
64 }
65 }
66 }
67
68 pub fn sub(&self, other: &Value) -> Result<Value, WError> {
69 match (&self.inner, &other.inner) {
70 (PallasValue::Coin(a), PallasValue::Coin(b)) => Ok(Value {
71 inner: PallasValue::Coin(a - b),
72 }),
73 (PallasValue::Coin(a), PallasValue::Multiasset(b, b_ma)) => Ok(Value {
74 inner: PallasValue::Multiasset(a - b, b_ma.clone()),
75 }),
76 (PallasValue::Multiasset(a, a_ma), PallasValue::Coin(b)) => Ok(Value {
77 inner: PallasValue::Multiasset(a - b, a_ma.clone()),
78 }),
79 (PallasValue::Multiasset(a, a_ma), PallasValue::Multiasset(b, b_ma)) => {
80 let mut combined_ma = a_ma.clone();
81 for (policy_id, assets) in b_ma.iter() {
82 if let Some(entry) = combined_ma.get_mut(policy_id) {
83 for (asset_name, amount) in assets.iter() {
84 if let Some(asset_entry) = entry.get_mut(asset_name) {
85 let new_amount = u64::from(*asset_entry) - u64::from(amount);
86 if new_amount == 0 {
87 entry.remove(asset_name);
88 } else {
89 *asset_entry = PositiveCoin::try_from(new_amount).map_err(|_| {
90 WError::new(
91 "Value - Sub:",
92 "Failed to create PositiveCoin from subtracted asset amounts",
93 )
94 })?;
95 }
96 }
97 }
98 }
99 }
100 for (policy_id, _assets) in b_ma.iter() {
101 if let Some(entry) = combined_ma.get_mut(policy_id) {
102 if entry.is_empty() {
103 combined_ma.remove(policy_id);
104 }
105 }
106 }
107 Ok(Value {
108 inner: PallasValue::Multiasset(a - b, combined_ma),
109 })
110 }
111 }
112 }
113
114 pub fn encode(&self) -> Result<String, WError> {
115 let bytes = self.inner.encode_fragment().map_err(|e| {
116 WError::new(
117 "Value - Encode:",
118 &format!("Fragment encoding failed: {}", e),
119 )
120 })?;
121 Ok(hex::encode(bytes))
122 }
123
124 pub fn decode_bytes(bytes: &[u8]) -> Result<Self, WError> {
125 let inner = PallasValue::decode_fragment(bytes).map_err(|e| {
126 WError::new("Value - Decode:", &format!("Fragment decode error: {}", e))
127 })?;
128 Ok(Self { inner })
129 }
130}