partner_chains_plutus_data/
reserve.rs1use crate::{
3 DataDecodingError, DecodingResult, VersionedDatum, VersionedGenericDatum,
4 decoding_error_and_log, plutus_data_version_and_payload,
5};
6use cardano_serialization_lib::{BigInt, BigNum, ConstrPlutusData, PlutusData, PlutusList};
7use sidechain_domain::{AssetId, AssetName, PolicyId};
8
9#[derive(Debug, Clone)]
10pub enum ReserveRedeemer {
12 DepositToReserve = 0,
14 ReleaseFromReserve = 1,
16 UpdateReserve = 2,
18 Handover = 3,
20}
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct ReserveDatum {
25 pub immutable_settings: ReserveImmutableSettings,
27 pub mutable_settings: ReserveMutableSettings,
29 pub stats: ReserveStats,
31}
32
33#[derive(Debug, Clone, PartialEq)]
34pub struct ReserveImmutableSettings {
36 pub token: AssetId,
38}
39
40#[derive(Debug, Clone, PartialEq)]
41pub struct ReserveMutableSettings {
43 pub total_accrued_function_asset_name: PolicyId,
48 pub initial_incentive: u64,
50}
51
52#[derive(Debug, Clone, PartialEq)]
53pub struct ReserveStats {
55 pub token_total_amount_transferred: u64,
57}
58
59impl From<ReserveRedeemer> for PlutusData {
60 fn from(value: ReserveRedeemer) -> Self {
61 PlutusData::new_empty_constr_plutus_data(&BigNum::from(value as u64))
62 }
63}
64
65impl From<ReserveDatum> for PlutusData {
66 fn from(value: ReserveDatum) -> Self {
67 VersionedGenericDatum {
68 datum: {
69 let (policy_id_bytes, asset_name_bytes) = {
70 let AssetId { policy_id, asset_name } = value.immutable_settings.token.clone();
71 (policy_id.0.to_vec(), asset_name.0.to_vec())
72 };
73 let token_data: PlutusData = {
74 let mut asset_data = PlutusList::new();
75 asset_data.add(&PlutusData::new_bytes(policy_id_bytes));
76 asset_data.add(&PlutusData::new_bytes(asset_name_bytes));
77 PlutusData::new_constr_plutus_data(&ConstrPlutusData::new(
78 &BigNum::zero(),
79 &asset_data,
80 ))
81 };
82
83 let mut v_function_hash_and_initial_incentive = PlutusList::new();
84 v_function_hash_and_initial_incentive.add(&PlutusData::new_bytes(
85 value.mutable_settings.total_accrued_function_asset_name.0.to_vec(),
86 ));
87 v_function_hash_and_initial_incentive.add(&PlutusData::new_integer(&BigInt::from(
88 value.mutable_settings.initial_incentive,
89 )));
90
91 let mut datum = PlutusList::new();
92 datum.add(&token_data);
93 datum.add(&PlutusData::new_list(&v_function_hash_and_initial_incentive));
94 datum.add(&PlutusData::new_integer(
95 &value.stats.token_total_amount_transferred.into(),
96 ));
97 PlutusData::new_list(&datum)
98 },
99 appendix: PlutusData::new_empty_constr_plutus_data(&BigNum::zero()),
101 version: 0,
102 }
103 .into()
104 }
105}
106
107impl TryFrom<PlutusData> for ReserveDatum {
108 type Error = DataDecodingError;
109
110 fn try_from(datum: PlutusData) -> DecodingResult<Self> {
111 Self::decode(&datum)
112 }
113}
114
115impl VersionedDatum for ReserveDatum {
116 fn decode(datum: &PlutusData) -> DecodingResult<Self> {
117 match plutus_data_version_and_payload(datum) {
118 Some(VersionedGenericDatum { version: 0, datum, .. }) => {
119 decode_v0_reserve_datum(&datum)
120 .ok_or_else(|| decoding_error_and_log(&datum, "ReserveDatum", "invalid data"))
121 },
122 _ => Err(decoding_error_and_log(datum, "ReserveDatum", "unversioned datum")),
123 }
124 }
125}
126
127impl ReserveDatum {
128 pub fn after_withdrawal(self, amount: u64) -> Self {
130 Self {
131 stats: ReserveStats {
132 token_total_amount_transferred: self.stats.token_total_amount_transferred + amount,
133 },
134 ..self
135 }
136 }
137}
138
139fn decode_v0_reserve_datum(datum: &PlutusData) -> Option<ReserveDatum> {
140 let outer_list = datum.as_list()?;
141 let mut outer_iter = outer_list.into_iter();
142
143 let token = decode_token_id_datum(outer_iter.next()?)?;
144
145 let mutable_settings_list = outer_iter.next()?.as_list()?;
146 let mut mutable_settings_iter = mutable_settings_list.into_iter();
147 let total_accrued_function_script_hash =
148 PolicyId(mutable_settings_iter.next()?.as_bytes()?.to_vec().try_into().ok()?);
149 let initial_incentive = mutable_settings_iter.next()?.as_integer()?.as_u64()?.into();
150
151 let stats = ReserveStats {
152 token_total_amount_transferred: outer_iter.next()?.as_integer()?.as_u64()?.into(),
153 };
154
155 Some(ReserveDatum {
156 immutable_settings: ReserveImmutableSettings { token },
157 mutable_settings: ReserveMutableSettings {
158 total_accrued_function_asset_name: total_accrued_function_script_hash,
159 initial_incentive,
160 },
161 stats,
162 })
163}
164
165fn decode_token_id_datum(pd: &PlutusData) -> Option<AssetId> {
166 let token_id_list = pd
167 .as_constr_plutus_data()
168 .filter(|constr| constr.alternative() == BigNum::zero())
169 .map(|constr| constr.data())?;
170 let mut token_id_list_iter = token_id_list.into_iter();
171 let policy_id = token_id_list_iter.next()?.as_bytes()?.to_vec();
172 let asset_name = token_id_list_iter.next()?.as_bytes()?.to_vec();
173 Some(AssetId {
174 policy_id: PolicyId(policy_id.try_into().ok()?),
175 asset_name: AssetName(asset_name.try_into().ok()?),
176 })
177}
178
179#[derive(Debug, Clone)]
180pub enum IlliquidCirculationSupplyRedeemer {
182 DepositMoreToSupply = 0,
184 WithdrawFromSupply = 1,
186}
187
188impl From<IlliquidCirculationSupplyRedeemer> for PlutusData {
189 fn from(value: IlliquidCirculationSupplyRedeemer) -> Self {
190 PlutusData::new_integer(&BigInt::from(value as u64))
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use cardano_serialization_lib::PlutusData;
197 use pretty_assertions::assert_eq;
198 use sidechain_domain::{AssetName, PolicyId};
199
200 use crate::test_helpers::test_plutus_data;
201
202 use super::{ReserveDatum, ReserveImmutableSettings, ReserveMutableSettings, ReserveStats};
203
204 fn test_reserve_datum() -> ReserveDatum {
205 ReserveDatum {
206 immutable_settings: ReserveImmutableSettings {
207 token: sidechain_domain::AssetId {
208 policy_id: PolicyId([0; 28]),
209 asset_name: AssetName::from_hex_unsafe("aabbcc"),
210 },
211 },
212 mutable_settings: ReserveMutableSettings {
213 total_accrued_function_asset_name: PolicyId([2; 28]),
214 initial_incentive: 0,
215 },
216 stats: ReserveStats { token_total_amount_transferred: 1000 },
217 }
218 }
219
220 fn test_reserve_datum_plutus_data() -> PlutusData {
221 test_plutus_data!({"list":[
222 {"list":[
223 {"constructor":0,
224 "fields":[
225 {"bytes": "00000000000000000000000000000000000000000000000000000000"},
226 {"bytes": "aabbcc"}]}
227 ,
228 {"list":[
229 {"bytes": "02020202020202020202020202020202020202020202020202020202"},
230 {"int": 0}
231 ]},
232 {"int": 1000}
233 ]},
234 {"constructor":0,"fields":[]},
235 {"int":0}
236 ]})
237 }
238
239 #[test]
240 fn encode_reserve_datum() {
241 assert_eq!(PlutusData::from(test_reserve_datum()), test_reserve_datum_plutus_data())
242 }
243
244 #[test]
245 fn decode_reserve_datum() {
246 assert_eq!(
247 ReserveDatum::try_from(test_reserve_datum_plutus_data()).unwrap(),
248 test_reserve_datum()
249 )
250 }
251}