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#[derive(Debug, Clone, PartialEq)]
195pub struct IlliquidCirculationSupplyDatum;
197
198impl From<IlliquidCirculationSupplyDatum> for PlutusData {
199 fn from(_value: IlliquidCirculationSupplyDatum) -> Self {
200 VersionedGenericDatum {
201 datum: PlutusData::new_empty_constr_plutus_data(
202 &cardano_serialization_lib::BigNum::zero(),
203 ),
204 appendix: PlutusData::new_empty_constr_plutus_data(
205 &cardano_serialization_lib::BigNum::zero(),
206 ),
207 version: 0,
208 }
209 .into()
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use cardano_serialization_lib::PlutusData;
216 use pretty_assertions::assert_eq;
217 use sidechain_domain::{AssetName, PolicyId};
218
219 use crate::{reserve::IlliquidCirculationSupplyDatum, test_helpers::test_plutus_data};
220
221 use super::{ReserveDatum, ReserveImmutableSettings, ReserveMutableSettings, ReserveStats};
222
223 fn test_reserve_datum() -> ReserveDatum {
224 ReserveDatum {
225 immutable_settings: ReserveImmutableSettings {
226 token: sidechain_domain::AssetId {
227 policy_id: PolicyId([0; 28]),
228 asset_name: AssetName::from_hex_unsafe("aabbcc"),
229 },
230 },
231 mutable_settings: ReserveMutableSettings {
232 total_accrued_function_asset_name: PolicyId([2; 28]),
233 initial_incentive: 0,
234 },
235 stats: ReserveStats { token_total_amount_transferred: 1000 },
236 }
237 }
238
239 fn test_reserve_datum_plutus_data() -> PlutusData {
240 test_plutus_data!({"list":[
241 {"list":[
242 {"constructor":0,
243 "fields":[
244 {"bytes": "00000000000000000000000000000000000000000000000000000000"},
245 {"bytes": "aabbcc"}]}
246 ,
247 {"list":[
248 {"bytes": "02020202020202020202020202020202020202020202020202020202"},
249 {"int": 0}
250 ]},
251 {"int": 1000}
252 ]},
253 {"constructor":0,"fields":[]},
254 {"int":0}
255 ]})
256 }
257
258 #[test]
259 fn encode_reserve_datum() {
260 assert_eq!(PlutusData::from(test_reserve_datum()), test_reserve_datum_plutus_data())
261 }
262
263 #[test]
264 fn decode_reserve_datum() {
265 assert_eq!(
266 ReserveDatum::try_from(test_reserve_datum_plutus_data()).unwrap(),
267 test_reserve_datum()
268 )
269 }
270
271 #[test]
272 fn encode_ics_datum() {
273 assert_eq!(
274 PlutusData::from(IlliquidCirculationSupplyDatum),
275 test_plutus_data!({"list":[
276 {"constructor":0,"fields":[]},
277 {"constructor":0,"fields":[]},
278 {"int":0}
279 ]})
280 )
281 }
282}