Skip to main content

cardano_serialization_lib/
lib.rs

1#![cfg_attr(all(test, feature = "with-bench"), feature(test))]
2#![allow(deprecated)]
3
4#[macro_use]
5extern crate cfg_if;
6
7#[cfg(test)]
8#[cfg(feature = "with-bench")]
9extern crate test;
10
11#[cfg(test)]
12extern crate quickcheck;
13#[cfg(test)]
14#[macro_use(quickcheck)]
15extern crate quickcheck_macros;
16extern crate hex;
17
18#[cfg(test)]
19mod tests;
20
21#[macro_use]
22extern crate num_derive;
23
24use std::convert::TryInto;
25use std::io::{BufRead, Seek, Write};
26
27#[cfg(any(not(all(target_arch = "wasm32", not(target_os = "emscripten"))), feature = "dont-expose-wasm"))]
28use noop_proc_macro::wasm_bindgen;
29
30use num_traits::SaturatingSub;
31#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten"), not(feature = "dont-expose-wasm")))]
32use wasm_bindgen::prelude::{wasm_bindgen, JsValue};
33
34// This file was code-generated using an experimental CDDL to rust tool:
35// https://github.com/Emurgo/cddl-codegen
36
37use cbor_event::{Len, Special as CBORSpecial};
38use cbor_event::Type as CBORType;
39use cbor_event::{
40    self,
41    de::Deserializer,
42    se::{Serialize, Serializer},
43};
44
45#[macro_use]
46mod macros;
47mod builders;
48pub use builders::*;
49pub mod chain_core;
50pub mod chain_crypto;
51mod crypto;
52pub(crate) use crypto::*;
53mod emip3;
54pub use emip3::*;
55mod error;
56pub use error::*;
57mod fees;
58pub use fees::*;
59pub mod impl_mockchain;
60pub mod legacy_address;
61pub mod traits;
62mod protocol_types;
63pub use protocol_types::*;
64pub mod typed_bytes;
65#[macro_use]
66mod utils;
67pub use utils::*;
68mod serialization;
69mod rational;
70
71pub use serialization::*;
72
73use crate::traits::NoneOrEmpty;
74use schemars::JsonSchema;
75use std::cmp::Ordering;
76use std::collections::BTreeSet;
77use std::fmt;
78use std::fmt::Display;
79use hashlink::LinkedHashMap;
80
81type DeltaCoin = Int;
82
83#[wasm_bindgen]
84#[derive(
85    Clone,
86    Debug,
87    Hash,
88    Eq,
89    Ord,
90    PartialEq,
91    PartialOrd,
92    Default,
93    serde::Serialize,
94    serde::Deserialize,
95    JsonSchema,
96)]
97pub struct UnitInterval {
98    numerator: BigNum,
99    denominator: BigNum,
100}
101
102impl_to_from!(UnitInterval);
103
104#[wasm_bindgen]
105impl UnitInterval {
106    pub fn numerator(&self) -> BigNum {
107        self.numerator.clone()
108    }
109
110    pub fn denominator(&self) -> BigNum {
111        self.denominator.clone()
112    }
113
114    pub fn new(numerator: &BigNum, denominator: &BigNum) -> Self {
115        Self {
116            numerator: numerator.clone(),
117            denominator: denominator.clone(),
118        }
119    }
120}
121
122type SubCoin = UnitInterval;
123type Epoch = u32;
124type Slot32 = u32;
125type SlotBigNum = BigNum;
126
127#[wasm_bindgen]
128#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, JsonSchema)]
129pub struct Transaction {
130    body: TransactionBody,
131    witness_set: TransactionWitnessSet,
132    is_valid: bool,
133    auxiliary_data: Option<AuxiliaryData>,
134}
135
136impl_to_from!(Transaction);
137
138#[wasm_bindgen]
139impl Transaction {
140    pub fn body(&self) -> TransactionBody {
141        self.body.clone()
142    }
143
144    pub fn witness_set(&self) -> TransactionWitnessSet {
145        self.witness_set.clone()
146    }
147
148    pub fn is_valid(&self) -> bool {
149        self.is_valid.clone()
150    }
151
152    pub fn auxiliary_data(&self) -> Option<AuxiliaryData> {
153        self.auxiliary_data.clone()
154    }
155
156    pub fn set_is_valid(&mut self, valid: bool) {
157        self.is_valid = valid
158    }
159
160    pub fn new(
161        body: &TransactionBody,
162        witness_set: &TransactionWitnessSet,
163        auxiliary_data: Option<AuxiliaryData>,
164    ) -> Self {
165        Self {
166            body: body.clone(),
167            witness_set: witness_set.clone(),
168            is_valid: true,
169            auxiliary_data: auxiliary_data.clone(),
170        }
171    }
172}
173
174// index of a tx within a block
175type TransactionIndex = u32;
176// index of a cert within a tx
177type CertificateIndex = u32;
178type GovernanceActionIndex = u32;
179
180#[wasm_bindgen]
181#[derive(Clone, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize, JsonSchema)]
182pub struct TransactionOutputs(Vec<TransactionOutput>);
183
184impl_to_from!(TransactionOutputs);
185
186#[wasm_bindgen]
187impl TransactionOutputs {
188    pub fn new() -> Self {
189        Self(Vec::new())
190    }
191
192    pub fn len(&self) -> usize {
193        self.0.len()
194    }
195
196    pub fn get(&self, index: usize) -> TransactionOutput {
197        self.0[index].clone()
198    }
199
200    pub fn add(&mut self, elem: &TransactionOutput) {
201        self.0.push(elem.clone());
202    }
203}
204
205impl_vec_wrapper!(TransactionOutputs, TransactionOutput);
206
207#[wasm_bindgen]
208#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
209pub struct DataCost{
210    coins_per_byte: Coin
211}
212
213#[wasm_bindgen]
214impl DataCost {
215    pub fn new_coins_per_byte(coins_per_byte: &Coin) -> DataCost {
216        DataCost {
217            coins_per_byte: coins_per_byte.clone()
218        }
219    }
220
221    pub fn coins_per_byte(&self) -> Coin {
222        self.coins_per_byte.clone()
223    }
224}
225
226#[wasm_bindgen]
227#[derive(Debug, Clone, Eq, Ord, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema)]
228pub struct TransactionOutput {
229    address: Address,
230    amount: Value,
231    plutus_data: Option<DataOption>,
232    script_ref: Option<ScriptRef>,
233
234    #[serde(skip)]
235    serialization_format: Option<CborContainerType>,
236}
237
238impl_to_from!(TransactionOutput);
239
240#[wasm_bindgen]
241impl TransactionOutput {
242    pub fn address(&self) -> Address {
243        self.address.clone()
244    }
245
246    pub fn amount(&self) -> Value {
247        self.amount.clone()
248    }
249
250    pub fn data_hash(&self) -> Option<DataHash> {
251        match &self.plutus_data {
252            Some(DataOption::DataHash(data_hash)) => Some(data_hash.clone()),
253            _ => None,
254        }
255    }
256
257    pub fn plutus_data(&self) -> Option<PlutusData> {
258        match &self.plutus_data {
259            Some(DataOption::Data(plutus_data)) => Some(plutus_data.clone()),
260            _ => None,
261        }
262    }
263
264    pub fn script_ref(&self) -> Option<ScriptRef> {
265        self.script_ref.clone()
266    }
267
268    pub fn set_script_ref(&mut self, script_ref: &ScriptRef) {
269        self.script_ref = Some(script_ref.clone());
270    }
271
272    pub fn set_plutus_data(&mut self, data: &PlutusData) {
273        self.plutus_data = Some(DataOption::Data(data.clone()));
274    }
275
276    pub fn set_data_hash(&mut self, data_hash: &DataHash) {
277        self.plutus_data = Some(DataOption::DataHash(data_hash.clone()));
278    }
279
280    pub fn has_plutus_data(&self) -> bool {
281        match &self.plutus_data {
282            Some(DataOption::Data(_)) => true,
283            _ => false,
284        }
285    }
286
287    pub fn has_data_hash(&self) -> bool {
288        match &self.plutus_data {
289            Some(DataOption::DataHash(_)) => true,
290            _ => false,
291        }
292    }
293
294    pub fn has_script_ref(&self) -> bool {
295        self.script_ref.is_some()
296    }
297
298    pub fn new(address: &Address, amount: &Value) -> Self {
299        Self {
300            address: address.clone(),
301            amount: amount.clone(),
302            plutus_data: None,
303            script_ref: None,
304            serialization_format: None,
305        }
306    }
307
308    pub fn serialization_format(&self) -> Option<CborContainerType> {
309        self.serialization_format.clone()
310    }
311}
312
313impl PartialEq for TransactionOutput {
314    fn eq(&self, other: &Self) -> bool {
315        self.address == other.address
316            && self.amount == other.amount
317            && self.plutus_data == other.plutus_data
318            && self.script_ref == other.script_ref
319    }
320}
321
322type Port = u16;
323
324#[wasm_bindgen]
325#[derive(
326    Clone,
327    Debug,
328    Hash,
329    Eq,
330    Ord,
331    PartialEq,
332    PartialOrd,
333    serde::Serialize,
334    serde::Deserialize,
335    JsonSchema,
336)]
337pub struct Ipv4([u8; 4]);
338
339impl_to_from!(Ipv4);
340
341#[wasm_bindgen]
342impl Ipv4 {
343    pub fn new(data: Vec<u8>) -> Result<Ipv4, JsError> {
344        Self::new_impl(data).map_err(|e| JsError::from_str(&e.to_string()))
345    }
346
347    pub(crate) fn new_impl(data: Vec<u8>) -> Result<Ipv4, DeserializeError> {
348        data.as_slice().try_into().map(Self).map_err(|_e| {
349            let cbor_error = cbor_event::Error::WrongLen(
350                4,
351                cbor_event::Len::Len(data.len() as u64),
352                "Ipv4 address length",
353            );
354            DeserializeError::new("Ipv4", DeserializeFailure::CBOR(cbor_error))
355        })
356    }
357
358    pub fn ip(&self) -> Vec<u8> {
359        self.0.to_vec()
360    }
361}
362
363#[wasm_bindgen]
364#[derive(
365    Clone,
366    Debug,
367    Hash,
368    Eq,
369    Ord,
370    PartialEq,
371    PartialOrd,
372    serde::Serialize,
373    serde::Deserialize,
374    JsonSchema,
375)]
376pub struct Ipv6([u8; 16]);
377
378impl_to_from!(Ipv6);
379
380#[wasm_bindgen]
381impl Ipv6 {
382    pub fn new(data: Vec<u8>) -> Result<Ipv6, JsError> {
383        Self::new_impl(data).map_err(|e| JsError::from_str(&e.to_string()))
384    }
385
386    pub(crate) fn new_impl(data: Vec<u8>) -> Result<Ipv6, DeserializeError> {
387        data.as_slice().try_into().map(Self).map_err(|_e| {
388            let cbor_error = cbor_event::Error::WrongLen(
389                16,
390                cbor_event::Len::Len(data.len() as u64),
391                "Ipv6 address length",
392            );
393            DeserializeError::new("Ipv6", DeserializeFailure::CBOR(cbor_error))
394        })
395    }
396
397    pub fn ip(&self) -> Vec<u8> {
398        self.0.to_vec()
399    }
400}
401
402static URL_MAX_LEN: usize = 128;
403
404#[wasm_bindgen]
405#[derive(
406    Clone,
407    Debug,
408    Hash,
409    Eq,
410    Ord,
411    PartialEq,
412    PartialOrd,
413    serde::Serialize,
414    serde::Deserialize,
415    JsonSchema,
416)]
417pub struct URL(String);
418
419impl_to_from!(URL);
420
421#[wasm_bindgen]
422impl URL {
423    pub fn new(url: String) -> Result<URL, JsError> {
424        Self::new_impl(url).map_err(|e| JsError::from_str(&e.to_string()))
425    }
426
427    pub(crate) fn new_impl(url: String) -> Result<URL, DeserializeError> {
428        if url.len() <= URL_MAX_LEN {
429            Ok(Self(url))
430        } else {
431            Err(DeserializeError::new(
432                "URL",
433                DeserializeFailure::OutOfRange {
434                    min: 0,
435                    max: URL_MAX_LEN,
436                    found: url.len(),
437                },
438            ))
439        }
440    }
441
442    pub fn url(&self) -> String {
443        self.0.clone()
444    }
445}
446
447static DNS_NAME_MAX_LEN: usize = 128;
448
449#[wasm_bindgen]
450#[derive(
451    Clone,
452    Debug,
453    Hash,
454    Eq,
455    Ord,
456    PartialEq,
457    PartialOrd,
458    serde::Serialize,
459    serde::Deserialize,
460    JsonSchema,
461)]
462pub struct DNSRecordAorAAAA(String);
463
464impl_to_from!(DNSRecordAorAAAA);
465
466#[wasm_bindgen]
467impl DNSRecordAorAAAA {
468    pub fn new(dns_name: String) -> Result<DNSRecordAorAAAA, JsError> {
469        Self::new_impl(dns_name).map_err(|e| JsError::from_str(&e.to_string()))
470    }
471
472    pub(crate) fn new_impl(dns_name: String) -> Result<DNSRecordAorAAAA, DeserializeError> {
473        if dns_name.len() <= DNS_NAME_MAX_LEN {
474            Ok(Self(dns_name))
475        } else {
476            Err(DeserializeError::new(
477                "DNSRecordAorAAAA",
478                DeserializeFailure::OutOfRange {
479                    min: 0,
480                    max: DNS_NAME_MAX_LEN,
481                    found: dns_name.len(),
482                },
483            ))
484        }
485    }
486
487    pub fn record(&self) -> String {
488        self.0.clone()
489    }
490}
491
492#[wasm_bindgen]
493#[derive(
494    Clone,
495    Debug,
496    Hash,
497    Eq,
498    Ord,
499    PartialEq,
500    PartialOrd,
501    serde::Serialize,
502    serde::Deserialize,
503    JsonSchema,
504)]
505pub struct DNSRecordSRV(String);
506
507impl_to_from!(DNSRecordSRV);
508
509#[wasm_bindgen]
510impl DNSRecordSRV {
511    pub fn new(dns_name: String) -> Result<DNSRecordSRV, JsError> {
512        Self::new_impl(dns_name).map_err(|e| JsError::from_str(&e.to_string()))
513    }
514
515    pub(crate) fn new_impl(dns_name: String) -> Result<DNSRecordSRV, DeserializeError> {
516        if dns_name.len() <= DNS_NAME_MAX_LEN {
517            Ok(Self(dns_name))
518        } else {
519            Err(DeserializeError::new(
520                "DNSRecordSRV",
521                DeserializeFailure::OutOfRange {
522                    min: 0,
523                    max: DNS_NAME_MAX_LEN,
524                    found: dns_name.len(),
525                },
526            ))
527        }
528    }
529
530    pub fn record(&self) -> String {
531        self.0.clone()
532    }
533}
534
535#[wasm_bindgen]
536#[derive(
537    Clone,
538    Debug,
539    Hash,
540    Eq,
541    Ord,
542    PartialEq,
543    PartialOrd,
544    serde::Serialize,
545    serde::Deserialize,
546    JsonSchema,
547)]
548pub struct SingleHostAddr {
549    port: Option<Port>,
550    ipv4: Option<Ipv4>,
551    ipv6: Option<Ipv6>,
552}
553
554impl_to_from!(SingleHostAddr);
555
556#[wasm_bindgen]
557impl SingleHostAddr {
558    pub fn port(&self) -> Option<Port> {
559        self.port.clone()
560    }
561
562    pub fn ipv4(&self) -> Option<Ipv4> {
563        self.ipv4.clone()
564    }
565
566    pub fn ipv6(&self) -> Option<Ipv6> {
567        self.ipv6.clone()
568    }
569
570    pub fn new(port: Option<Port>, ipv4: Option<Ipv4>, ipv6: Option<Ipv6>) -> Self {
571        Self {
572            port: port,
573            ipv4: ipv4.clone(),
574            ipv6: ipv6.clone(),
575        }
576    }
577}
578
579#[wasm_bindgen]
580#[derive(
581    Clone,
582    Debug,
583    Hash,
584    Eq,
585    Ord,
586    PartialEq,
587    PartialOrd,
588    serde::Serialize,
589    serde::Deserialize,
590    JsonSchema,
591)]
592pub struct SingleHostName {
593    port: Option<Port>,
594    dns_name: DNSRecordAorAAAA,
595}
596
597impl_to_from!(SingleHostName);
598
599#[wasm_bindgen]
600impl SingleHostName {
601    pub fn port(&self) -> Option<Port> {
602        self.port.clone()
603    }
604
605    pub fn dns_name(&self) -> DNSRecordAorAAAA {
606        self.dns_name.clone()
607    }
608
609    pub fn new(port: Option<Port>, dns_name: &DNSRecordAorAAAA) -> Self {
610        Self {
611            port: port,
612            dns_name: dns_name.clone(),
613        }
614    }
615}
616
617#[wasm_bindgen]
618#[derive(
619    Clone,
620    Debug,
621    Hash,
622    Eq,
623    Ord,
624    PartialEq,
625    PartialOrd,
626    serde::Serialize,
627    serde::Deserialize,
628    JsonSchema,
629)]
630pub struct MultiHostName {
631    dns_name: DNSRecordSRV,
632}
633
634impl_to_from!(MultiHostName);
635
636#[wasm_bindgen]
637impl MultiHostName {
638    pub fn dns_name(&self) -> DNSRecordSRV {
639        self.dns_name.clone()
640    }
641
642    pub fn new(dns_name: &DNSRecordSRV) -> Self {
643        Self {
644            dns_name: dns_name.clone(),
645        }
646    }
647}
648
649#[wasm_bindgen]
650#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
651pub enum RelayKind {
652    SingleHostAddr,
653    SingleHostName,
654    MultiHostName,
655}
656
657#[derive(
658    Clone,
659    Debug,
660    Hash,
661    Eq,
662    Ord,
663    PartialEq,
664    PartialOrd,
665    serde::Serialize,
666    serde::Deserialize,
667    JsonSchema,
668)]
669pub enum RelayEnum {
670    SingleHostAddr(SingleHostAddr),
671    SingleHostName(SingleHostName),
672    MultiHostName(MultiHostName),
673}
674
675#[wasm_bindgen]
676#[derive(
677    Clone,
678    Debug,
679    Hash,
680    Eq,
681    Ord,
682    PartialEq,
683    PartialOrd,
684    serde::Serialize,
685    serde::Deserialize,
686    JsonSchema,
687)]
688pub struct Relay(RelayEnum);
689
690impl_to_from!(Relay);
691
692#[wasm_bindgen]
693impl Relay {
694    pub fn new_single_host_addr(single_host_addr: &SingleHostAddr) -> Self {
695        Self(RelayEnum::SingleHostAddr(single_host_addr.clone()))
696    }
697
698    pub fn new_single_host_name(single_host_name: &SingleHostName) -> Self {
699        Self(RelayEnum::SingleHostName(single_host_name.clone()))
700    }
701
702    pub fn new_multi_host_name(multi_host_name: &MultiHostName) -> Self {
703        Self(RelayEnum::MultiHostName(multi_host_name.clone()))
704    }
705
706    pub fn kind(&self) -> RelayKind {
707        match &self.0 {
708            RelayEnum::SingleHostAddr(_) => RelayKind::SingleHostAddr,
709            RelayEnum::SingleHostName(_) => RelayKind::SingleHostName,
710            RelayEnum::MultiHostName(_) => RelayKind::MultiHostName,
711        }
712    }
713
714    pub fn as_single_host_addr(&self) -> Option<SingleHostAddr> {
715        match &self.0 {
716            RelayEnum::SingleHostAddr(x) => Some(x.clone()),
717            _ => None,
718        }
719    }
720
721    pub fn as_single_host_name(&self) -> Option<SingleHostName> {
722        match &self.0 {
723            RelayEnum::SingleHostName(x) => Some(x.clone()),
724            _ => None,
725        }
726    }
727
728    pub fn as_multi_host_name(&self) -> Option<MultiHostName> {
729        match &self.0 {
730            RelayEnum::MultiHostName(x) => Some(x.clone()),
731            _ => None,
732        }
733    }
734}
735
736#[wasm_bindgen]
737#[derive(
738    Clone,
739    Debug,
740    Hash,
741    Eq,
742    Ord,
743    PartialEq,
744    PartialOrd,
745    serde::Serialize,
746    serde::Deserialize,
747    JsonSchema,
748)]
749pub struct PoolMetadata {
750    url: URL,
751    pool_metadata_hash: PoolMetadataHash,
752}
753
754impl_to_from!(PoolMetadata);
755
756#[wasm_bindgen]
757impl PoolMetadata {
758    pub fn url(&self) -> URL {
759        self.url.clone()
760    }
761
762    pub fn pool_metadata_hash(&self) -> PoolMetadataHash {
763        self.pool_metadata_hash.clone()
764    }
765
766    pub fn new(url: &URL, pool_metadata_hash: &PoolMetadataHash) -> Self {
767        Self {
768            url: url.clone(),
769            pool_metadata_hash: pool_metadata_hash.clone(),
770        }
771    }
772}
773
774#[wasm_bindgen]
775#[derive(
776    Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
777)]
778pub struct RewardAddresses(pub(crate) Vec<RewardAddress>);
779
780impl_to_from!(RewardAddresses);
781
782#[wasm_bindgen]
783impl RewardAddresses {
784    pub fn new() -> Self {
785        Self(Vec::new())
786    }
787
788    pub fn len(&self) -> usize {
789        self.0.len()
790    }
791
792    pub fn get(&self, index: usize) -> RewardAddress {
793        self.0[index].clone()
794    }
795
796    pub fn add(&mut self, elem: &RewardAddress) {
797        self.0.push(elem.clone());
798    }
799}
800
801impl_vec_wrapper!(RewardAddresses, RewardAddress);
802
803#[wasm_bindgen]
804#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
805pub struct Withdrawals(LinkedHashMap<RewardAddress, Coin>);
806
807impl_to_from!(Withdrawals);
808
809impl NoneOrEmpty for Withdrawals {
810    fn is_none_or_empty(&self) -> bool {
811        self.0.is_empty()
812    }
813}
814
815#[wasm_bindgen]
816impl Withdrawals {
817    pub fn new() -> Self {
818        Self(LinkedHashMap::new())
819    }
820
821    pub fn len(&self) -> usize {
822        self.0.len()
823    }
824
825    pub fn insert(&mut self, key: &RewardAddress, value: &Coin) -> Option<Coin> {
826        self.0.insert(key.clone(), value.clone())
827    }
828
829    pub fn get(&self, key: &RewardAddress) -> Option<Coin> {
830        self.0.get(key).map(|v| v.clone())
831    }
832
833    pub fn keys(&self) -> RewardAddresses {
834        RewardAddresses(
835            self.0
836                .iter()
837                .map(|(k, _v)| k.clone())
838                .collect::<Vec<RewardAddress>>(),
839        )
840    }
841
842    #[allow(dead_code)]
843    pub(crate) fn as_vec(&self) -> Vec<(&RewardAddress, &Coin)> {
844        self.0.iter().collect()
845    }
846}
847
848impl serde::Serialize for Withdrawals {
849    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
850    where
851        S: serde::Serializer,
852    {
853        let map = self.0.iter().collect::<std::collections::BTreeMap<_, _>>();
854        map.serialize(serializer)
855    }
856}
857
858impl<'de> serde::de::Deserialize<'de> for Withdrawals {
859    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
860    where
861        D: serde::de::Deserializer<'de>,
862    {
863        let map = <std::collections::BTreeMap<_, _> as serde::de::Deserialize>::deserialize(
864            deserializer,
865        )?;
866        Ok(Self(map.into_iter().collect()))
867    }
868}
869
870impl JsonSchema for Withdrawals {
871    fn schema_name() -> String {
872        String::from("Withdrawals")
873    }
874    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
875        std::collections::BTreeMap::<RewardAddress, Coin>::json_schema(gen)
876    }
877    fn is_referenceable() -> bool {
878        std::collections::BTreeMap::<RewardAddress, Coin>::is_referenceable()
879    }
880}
881
882#[derive(
883    Debug, Clone, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
884)]
885pub enum DataOption {
886    DataHash(DataHash),
887    Data(PlutusData),
888}
889
890#[wasm_bindgen]
891#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
892pub struct OutputDatum(pub(crate) DataOption);
893
894#[wasm_bindgen]
895impl OutputDatum {
896    pub fn new_data_hash(data_hash: &DataHash) -> Self {
897        Self(DataOption::DataHash(data_hash.clone()))
898    }
899
900    pub fn new_data(data: &PlutusData) -> Self {
901        Self(DataOption::Data(data.clone()))
902    }
903
904    pub fn data_hash(&self) -> Option<DataHash> {
905        match &self.0 {
906            DataOption::DataHash(data_hash) => Some(data_hash.clone()),
907            _ => None,
908        }
909    }
910
911    pub fn data(&self) -> Option<PlutusData> {
912        match &self.0 {
913            DataOption::Data(data) => Some(data.clone()),
914            _ => None,
915        }
916    }
917}
918
919/// Each new language uses a different namespace for hashing its script
920/// This is because you could have a language where the same bytes have different semantics
921/// So this avoids scripts in different languages mapping to the same hash
922/// Note that the enum value here is different than the enum value for deciding the cost model of a script
923#[wasm_bindgen]
924#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
925pub enum ScriptHashNamespace {
926    NativeScript = 0,
927    PlutusScript = 1,
928    PlutusScriptV2 = 2,
929    PlutusScriptV3 = 3,
930}
931
932#[wasm_bindgen]
933#[derive(
934    Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
935)]
936pub struct Update {
937    proposed_protocol_parameter_updates: ProposedProtocolParameterUpdates,
938    epoch: Epoch,
939}
940
941impl_to_from!(Update);
942
943#[wasm_bindgen]
944impl Update {
945    pub fn proposed_protocol_parameter_updates(&self) -> ProposedProtocolParameterUpdates {
946        self.proposed_protocol_parameter_updates.clone()
947    }
948
949    pub fn epoch(&self) -> Epoch {
950        self.epoch.clone()
951    }
952
953    pub fn new(
954        proposed_protocol_parameter_updates: &ProposedProtocolParameterUpdates,
955        epoch: Epoch,
956    ) -> Self {
957        Self {
958            proposed_protocol_parameter_updates: proposed_protocol_parameter_updates.clone(),
959            epoch: epoch.clone(),
960        }
961    }
962}
963
964#[wasm_bindgen]
965#[derive(
966    Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
967)]
968pub struct GenesisHashes(Vec<GenesisHash>);
969
970impl_to_from!(GenesisHashes);
971
972#[wasm_bindgen]
973impl GenesisHashes {
974    pub fn new() -> Self {
975        Self(Vec::new())
976    }
977
978    pub fn len(&self) -> usize {
979        self.0.len()
980    }
981
982    pub fn get(&self, index: usize) -> GenesisHash {
983        self.0[index].clone()
984    }
985
986    pub fn add(&mut self, elem: &GenesisHash) {
987        self.0.push(elem.clone());
988    }
989}
990
991impl_vec_wrapper!(GenesisHashes, GenesisHash);
992
993#[wasm_bindgen]
994#[derive(
995    Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
996)]
997pub struct ScriptHashes(pub(crate) Vec<ScriptHash>);
998
999impl_to_from!(ScriptHashes);
1000
1001#[wasm_bindgen]
1002impl ScriptHashes {
1003    pub fn new() -> Self {
1004        Self(Vec::new())
1005    }
1006
1007    pub fn len(&self) -> usize {
1008        self.0.len()
1009    }
1010
1011    pub fn get(&self, index: usize) -> ScriptHash {
1012        self.0[index].clone()
1013    }
1014
1015    pub fn add(&mut self, elem: &ScriptHash) {
1016        self.0.push(elem.clone());
1017    }
1018}
1019
1020impl_vec_wrapper!(ScriptHashes, ScriptHash);
1021
1022#[wasm_bindgen]
1023#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
1024pub struct ProposedProtocolParameterUpdates(
1025    LinkedHashMap<GenesisHash, ProtocolParamUpdate>,
1026);
1027
1028impl serde::Serialize for ProposedProtocolParameterUpdates {
1029    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1030    where
1031        S: serde::Serializer,
1032    {
1033        let map = self.0.iter().collect::<std::collections::BTreeMap<_, _>>();
1034        map.serialize(serializer)
1035    }
1036}
1037
1038impl<'de> serde::de::Deserialize<'de> for ProposedProtocolParameterUpdates {
1039    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1040    where
1041        D: serde::de::Deserializer<'de>,
1042    {
1043        let map = <std::collections::BTreeMap<_, _> as serde::de::Deserialize>::deserialize(
1044            deserializer,
1045        )?;
1046        Ok(Self(map.into_iter().collect()))
1047    }
1048}
1049
1050impl JsonSchema for ProposedProtocolParameterUpdates {
1051    fn schema_name() -> String {
1052        String::from("ProposedProtocolParameterUpdates")
1053    }
1054    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1055        std::collections::BTreeMap::<GenesisHash, ProtocolParamUpdate>::json_schema(gen)
1056    }
1057    fn is_referenceable() -> bool {
1058        std::collections::BTreeMap::<GenesisHash, ProtocolParamUpdate>::is_referenceable()
1059    }
1060}
1061
1062impl_to_from!(ProposedProtocolParameterUpdates);
1063
1064#[wasm_bindgen]
1065impl ProposedProtocolParameterUpdates {
1066    pub fn new() -> Self {
1067        Self(LinkedHashMap::new())
1068    }
1069
1070    pub fn len(&self) -> usize {
1071        self.0.len()
1072    }
1073
1074    pub fn insert(
1075        &mut self,
1076        key: &GenesisHash,
1077        value: &ProtocolParamUpdate,
1078    ) -> Option<ProtocolParamUpdate> {
1079        self.0.insert(key.clone(), value.clone())
1080    }
1081
1082    pub fn get(&self, key: &GenesisHash) -> Option<ProtocolParamUpdate> {
1083        self.0.get(key).map(|v| v.clone())
1084    }
1085
1086    pub fn keys(&self) -> GenesisHashes {
1087        GenesisHashes(
1088            self.0
1089                .iter()
1090                .map(|(k, _v)| k.clone())
1091                .collect::<Vec<GenesisHash>>(),
1092        )
1093    }
1094}
1095
1096#[wasm_bindgen]
1097#[derive(
1098    Clone,
1099    Debug,
1100    Hash,
1101    Eq,
1102    Ord,
1103    PartialEq,
1104    PartialOrd,
1105    serde::Serialize,
1106    serde::Deserialize,
1107    JsonSchema,
1108)]
1109pub struct ProtocolVersion {
1110    major: u32,
1111    minor: u32,
1112}
1113
1114impl_to_from!(ProtocolVersion);
1115
1116#[wasm_bindgen]
1117impl ProtocolVersion {
1118    pub fn major(&self) -> u32 {
1119        self.major
1120    }
1121
1122    pub fn minor(&self) -> u32 {
1123        self.minor
1124    }
1125
1126    pub fn new(major: u32, minor: u32) -> Self {
1127        Self { major, minor }
1128    }
1129}
1130
1131#[wasm_bindgen]
1132#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
1133pub struct AuxiliaryDataSet(LinkedHashMap<TransactionIndex, AuxiliaryData>);
1134
1135#[wasm_bindgen]
1136impl AuxiliaryDataSet {
1137    pub fn new() -> Self {
1138        Self(LinkedHashMap::new())
1139    }
1140
1141    pub fn len(&self) -> usize {
1142        self.0.len()
1143    }
1144
1145    pub fn insert(
1146        &mut self,
1147        tx_index: TransactionIndex,
1148        data: &AuxiliaryData,
1149    ) -> Option<AuxiliaryData> {
1150        self.0.insert(tx_index, data.clone())
1151    }
1152
1153    pub fn get(&self, tx_index: TransactionIndex) -> Option<AuxiliaryData> {
1154        self.0.get(&tx_index).map(|v| v.clone())
1155    }
1156
1157    pub fn indices(&self) -> TransactionIndexes {
1158        self.0
1159            .iter()
1160            .map(|(k, _v)| k.clone())
1161            .collect::<Vec<TransactionIndex>>()
1162    }
1163}
1164
1165impl serde::Serialize for AuxiliaryDataSet {
1166    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1167    where
1168        S: serde::Serializer,
1169    {
1170        let map = self.0.iter().collect::<std::collections::BTreeMap<_, _>>();
1171        map.serialize(serializer)
1172    }
1173}
1174
1175impl<'de> serde::de::Deserialize<'de> for AuxiliaryDataSet {
1176    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1177    where
1178        D: serde::de::Deserializer<'de>,
1179    {
1180        let map = <std::collections::BTreeMap<_, _> as serde::de::Deserialize>::deserialize(
1181            deserializer,
1182        )?;
1183        Ok(Self(map.into_iter().collect()))
1184    }
1185}
1186
1187impl JsonSchema for AuxiliaryDataSet {
1188    fn schema_name() -> String {
1189        String::from("AuxiliaryDataSet")
1190    }
1191    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1192        std::collections::BTreeMap::<TransactionIndex, AuxiliaryData>::json_schema(gen)
1193    }
1194    fn is_referenceable() -> bool {
1195        std::collections::BTreeMap::<TransactionIndex, AuxiliaryData>::is_referenceable()
1196    }
1197}
1198
1199#[wasm_bindgen]
1200#[derive(Clone, Debug, Eq, PartialEq, Hash)]
1201pub struct AssetName(Vec<u8>);
1202
1203impl Display for AssetName {
1204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1205        write!(f, "{}", hex::encode(&self.0))
1206    }
1207}
1208
1209impl Ord for AssetName {
1210    fn cmp(&self, other: &Self) -> Ordering {
1211        // Implementing canonical CBOR order for asset names,
1212        // as they might be of different length.
1213        return match self.0.len().cmp(&other.0.len()) {
1214            Ordering::Equal => self.0.cmp(&other.0),
1215            x => x,
1216        };
1217    }
1218}
1219
1220impl PartialOrd for AssetName {
1221    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1222        Some(self.cmp(other))
1223    }
1224}
1225
1226impl_to_from!(AssetName);
1227
1228#[wasm_bindgen]
1229impl AssetName {
1230    pub fn new(name: Vec<u8>) -> Result<AssetName, JsError> {
1231        Self::new_impl(name).map_err(|e| JsError::from_str(&e.to_string()))
1232    }
1233
1234    pub(crate) fn new_impl(name: Vec<u8>) -> Result<AssetName, DeserializeError> {
1235        if name.len() <= 32 {
1236            Ok(Self(name))
1237        } else {
1238            Err(DeserializeError::new(
1239                "AssetName",
1240                DeserializeFailure::OutOfRange {
1241                    min: 0,
1242                    max: 32,
1243                    found: name.len(),
1244                },
1245            ))
1246        }
1247    }
1248
1249    pub fn name(&self) -> Vec<u8> {
1250        self.0.clone()
1251    }
1252}
1253
1254impl serde::Serialize for AssetName {
1255    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1256    where
1257        S: serde::Serializer,
1258    {
1259        serializer.serialize_str(&hex::encode(&self.0))
1260    }
1261}
1262
1263impl<'de> serde::de::Deserialize<'de> for AssetName {
1264    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1265    where
1266        D: serde::de::Deserializer<'de>,
1267    {
1268        let s = <String as serde::de::Deserialize>::deserialize(deserializer)?;
1269        if let Ok(bytes) = hex::decode(&s) {
1270            if let Ok(asset_name) = AssetName::new(bytes) {
1271                return Ok(asset_name);
1272            }
1273        }
1274        Err(serde::de::Error::invalid_value(
1275            serde::de::Unexpected::Str(&s),
1276            &"AssetName as hex string e.g. F8AB28C2",
1277        ))
1278    }
1279}
1280
1281impl JsonSchema for AssetName {
1282    fn schema_name() -> String {
1283        String::from("AssetName")
1284    }
1285    fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
1286        String::json_schema(gen)
1287    }
1288    fn is_referenceable() -> bool {
1289        String::is_referenceable()
1290    }
1291}
1292
1293#[wasm_bindgen]
1294#[derive(
1295    Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
1296)]
1297pub struct AssetNames(Vec<AssetName>);
1298
1299impl_to_from!(AssetNames);
1300
1301#[wasm_bindgen]
1302impl AssetNames {
1303    pub fn new() -> Self {
1304        Self(Vec::new())
1305    }
1306
1307    pub fn len(&self) -> usize {
1308        self.0.len()
1309    }
1310
1311    pub fn get(&self, index: usize) -> AssetName {
1312        self.0[index].clone()
1313    }
1314
1315    pub fn add(&mut self, elem: &AssetName) {
1316        self.0.push(elem.clone());
1317    }
1318}
1319
1320impl_vec_wrapper!(AssetNames, AssetName);
1321
1322pub type PolicyID = ScriptHash;
1323pub type PolicyIDs = ScriptHashes;
1324
1325#[wasm_bindgen]
1326#[derive(
1327    Clone,
1328    Debug,
1329    Default,
1330    Eq,
1331    Ord,
1332    PartialEq,
1333    PartialOrd,
1334    serde::Serialize,
1335    serde::Deserialize,
1336    JsonSchema,
1337)]
1338pub struct Assets(pub(crate) std::collections::BTreeMap<AssetName, BigNum>);
1339
1340impl_to_from!(Assets);
1341impl_btmap_wrapper!(Assets, AssetName, BigNum);
1342
1343#[macro_export]
1344macro_rules! assets {
1345    ($($name:expr => $amount:expr),* $(,)?) => {
1346        $crate::Assets::new()
1347            $(.with_asset($crate::AssetName::from($name), $crate::BigNum::from($amount)))*
1348    };
1349}
1350
1351#[wasm_bindgen]
1352impl Assets {
1353    pub fn new() -> Self {
1354        Self(std::collections::BTreeMap::new())
1355    }
1356
1357    pub fn len(&self) -> usize {
1358        self.0.len()
1359    }
1360
1361    pub fn insert(&mut self, key: &AssetName, value: &BigNum) -> Option<BigNum> {
1362        self.0.insert(key.clone(), value.clone())
1363    }
1364
1365    pub fn get(&self, key: &AssetName) -> Option<BigNum> {
1366        self.0.get(key).map(|v| v.clone())
1367    }
1368
1369    pub fn keys(&self) -> AssetNames {
1370        AssetNames(
1371            self.0
1372                .iter()
1373                .map(|(k, _v)| k.clone())
1374                .collect::<Vec<AssetName>>(),
1375        )
1376    }
1377
1378    pub fn is_zero(&self) -> bool {
1379        self.0.values().all(BigNum::is_zero)
1380    }
1381}
1382
1383impl Assets {
1384    pub fn with_asset(mut self, name: AssetName, amount: BigNum) -> Self {
1385        if amount.is_zero() {
1386            self.0.remove(&name);
1387        } else {
1388            self.0.insert(name, amount);
1389        }
1390        self
1391    }
1392}
1393
1394#[wasm_bindgen]
1395#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, serde::Serialize, serde::Deserialize, JsonSchema)]
1396pub struct MultiAsset(pub(crate) std::collections::BTreeMap<PolicyID, Assets>);
1397
1398impl_to_from!(MultiAsset);
1399impl_btmap_wrapper!(MultiAsset, PolicyID, Assets, 0);
1400
1401#[macro_export]
1402macro_rules! multi_asset {
1403    ($($policy:expr => $assets:expr),* $(,)?) => {
1404        $crate::MultiAsset::new()
1405            $(.with_assets($crate::PolicyID::from($policy), $crate::Assets::from($assets)))*
1406    };
1407}
1408
1409#[wasm_bindgen]
1410impl MultiAsset {
1411    pub fn new() -> Self {
1412        Self(std::collections::BTreeMap::new())
1413    }
1414
1415    /// the number of unique policy IDs in the multiasset
1416    pub fn len(&self) -> usize {
1417        self.0.len()
1418    }
1419
1420    /// set (and replace if it exists) all assets with policy {policy_id} to a copy of {assets}
1421    pub fn insert(&mut self, policy_id: &PolicyID, assets: &Assets) -> Option<Assets> {
1422        self.0.insert(policy_id.clone(), assets.clone())
1423    }
1424
1425    /// all assets under {policy_id}, if any exist, or else None (undefined in JS)
1426    pub fn get(&self, policy_id: &PolicyID) -> Option<Assets> {
1427        self.0.get(policy_id).map(|v| v.clone())
1428    }
1429
1430    pub fn is_zero(&self) -> bool {
1431        self.0.values().all(Assets::is_zero)
1432    }
1433
1434    /// sets the asset {asset_name} to {value} under policy {policy_id}
1435    /// returns the previous amount if it was set, or else None (undefined in JS)
1436    pub fn set_asset(
1437        &mut self,
1438        policy_id: &PolicyID,
1439        asset_name: &AssetName,
1440        value: &BigNum,
1441    ) -> Option<BigNum> {
1442        self.0
1443            .entry(policy_id.clone())
1444            .or_default()
1445            .insert(asset_name, value)
1446    }
1447
1448    /// returns the amount of asset {asset_name} under policy {policy_id}
1449    /// If such an asset does not exist, 0 is returned.
1450    pub fn get_asset(&self, policy_id: &PolicyID, asset_name: &AssetName) -> BigNum {
1451        (|| self.0.get(policy_id)?.get(asset_name))().unwrap_or(BigNum::zero())
1452    }
1453
1454    /// returns all policy IDs used by assets in this multiasset
1455    pub fn keys(&self) -> PolicyIDs {
1456        ScriptHashes(
1457            self.0
1458                .iter()
1459                .map(|(k, _v)| k.clone())
1460                .collect::<Vec<PolicyID>>(),
1461        )
1462    }
1463
1464    /// removes an asset from the list if the result is 0 or less
1465    /// does not modify this object, instead the result is returned
1466    pub fn sub(&self, rhs_ma: &MultiAsset) -> MultiAsset {
1467        <Self as SaturatingSub>::saturating_sub(self, rhs_ma)
1468    }
1469
1470    pub(crate) fn reduce_empty_to_none(&self) -> Option<&MultiAsset> {
1471        for (_policy, assets) in self.0.iter() {
1472            if assets.len() > 0 {
1473                return Some(self);
1474            }
1475        }
1476
1477        None
1478    }
1479}
1480
1481impl MultiAsset {
1482    pub fn with_assets(mut self, policy: PolicyID, assets: Assets) -> Self {
1483        if assets.is_zero() {
1484            self.0.remove(&policy);
1485        } else {
1486            self.0.insert(policy, assets);
1487        }
1488        self
1489    }
1490
1491    pub fn with_asset(mut self, policy: PolicyID, name: AssetName, amount: BigNum) -> Self {
1492        let assets = self.0.remove(&policy).unwrap_or_default().with_asset(name, amount);
1493        self.with_assets(policy, assets)
1494    }
1495}
1496
1497// deriving PartialOrd doesn't work in a way that's useful , as the
1498// implementation of PartialOrd for BTreeMap compares keys by their order,
1499// i.e, is equivalent to comparing the iterators of (pid, Assets).
1500// that would mean that: v1 < v2 if the min_pid(v1) < min_pid(v2)
1501// this function instead compares amounts, assuming that if a pair (pid, aname)
1502// is not in the MultiAsset then it has an amount of 0
1503impl PartialOrd for MultiAsset {
1504    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1505        fn amount_or_zero(ma: &MultiAsset, pid: &PolicyID, aname: &AssetName) -> Coin {
1506            ma.get(&pid)
1507                .and_then(|assets| assets.get(aname))
1508                .unwrap_or(BigNum(0u64)) // assume 0 if asset not present
1509        }
1510
1511        // idea: if (a-b) > 0 for some asset, then a > b for at least some asset
1512        fn is_all_zeros(lhs: &MultiAsset, rhs: &MultiAsset) -> bool {
1513            for (pid, assets) in lhs.0.iter() {
1514                for (aname, amount) in assets.0.iter() {
1515                    match amount
1516                        .clamped_sub(&amount_or_zero(&rhs, pid, aname))
1517                        .cmp(&BigNum::zero())
1518                    {
1519                        std::cmp::Ordering::Equal => (),
1520                        _ => return false,
1521                    }
1522                }
1523            }
1524            true
1525        }
1526
1527        match (is_all_zeros(self, other), is_all_zeros(other, self)) {
1528            (true, true) => Some(std::cmp::Ordering::Equal),
1529            (true, false) => Some(std::cmp::Ordering::Less),
1530            (false, true) => Some(std::cmp::Ordering::Greater),
1531            (false, false) => None,
1532        }
1533    }
1534}
1535
1536#[wasm_bindgen]
1537#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema)]
1538pub struct MintsAssets(Vec<MintAssets>);
1539
1540to_from_json!(MintsAssets);
1541
1542#[wasm_bindgen]
1543impl MintsAssets {
1544    pub fn new() -> Self {
1545        Self(Vec::new())
1546    }
1547
1548    pub fn add(&mut self, mint_assets: &MintAssets) {
1549        self.0.push(mint_assets.clone())
1550    }
1551
1552    pub fn get(&self, index: usize) -> Option<MintAssets> {
1553        self.0.get(index).map(|v| v.clone())
1554    }
1555
1556    pub fn len(&self) -> usize {
1557        self.0.len()
1558    }
1559}
1560
1561impl_vec_wrapper!(MintsAssets, MintAssets);
1562
1563#[wasm_bindgen]
1564#[derive(
1565    Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
1566)]
1567pub struct MintAssets(std::collections::BTreeMap<AssetName, Int>);
1568
1569#[wasm_bindgen]
1570impl MintAssets {
1571    pub fn new() -> Self {
1572        Self(std::collections::BTreeMap::new())
1573    }
1574
1575    pub fn new_from_entry(key: &AssetName, value: &Int) -> Result<MintAssets, JsError> {
1576        let mut ma = MintAssets::new();
1577        ma.insert(key, value)?;
1578        Ok(ma)
1579    }
1580
1581    pub fn len(&self) -> usize {
1582        self.0.len()
1583    }
1584
1585    pub fn insert(&mut self, key: &AssetName, value: &Int) -> Result<Option<Int>, JsError> {
1586        if value.0 == 0 {
1587            return Err(JsError::from_str("MintAssets cannot be created with 0 value"));
1588        }
1589        // Conway CDDL: `mint = {+ policy_id => {+ asset_name => nonzero_int64}}`.
1590        // Mint amounts must fit in int64; values outside are not valid on-chain
1591        // and also cannot be converted to a `BigNum` burn amount in
1592        // `MultiAsset` further down the pipeline.
1593        if !value.fits_int64() {
1594            return Err(JsError::from_str(&format!(
1595                "MintAssets value {} is out of CDDL nonzero_int64 range [{}, -1] U [1, {}]",
1596                value.0,
1597                i64::MIN,
1598                i64::MAX,
1599            )));
1600        }
1601        Ok(self.0.insert(key.clone(), value.clone()))
1602    }
1603
1604    pub(crate) fn insert_unchecked(&mut self, key: &AssetName, value: Int) -> Option<Int> {
1605        self.0.insert(key.clone(), value)
1606    }
1607
1608    pub fn get(&self, key: &AssetName) -> Option<Int> {
1609        self.0.get(key).map(|v| v.clone())
1610    }
1611
1612    pub fn keys(&self) -> AssetNames {
1613        AssetNames(
1614            self.0
1615                .iter()
1616                .map(|(k, _v)| k.clone())
1617                .collect::<Vec<AssetName>>(),
1618        )
1619    }
1620}
1621
1622#[wasm_bindgen]
1623#[derive(
1624    Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize, JsonSchema,
1625)]
1626pub struct Mint(Vec<(PolicyID, MintAssets)>);
1627
1628impl_to_from!(Mint);
1629
1630impl NoneOrEmpty for Mint {
1631    fn is_none_or_empty(&self) -> bool {
1632        self.0.is_empty()
1633    }
1634}
1635
1636#[wasm_bindgen]
1637impl Mint {
1638    pub fn new() -> Self {
1639        Self(Vec::new())
1640    }
1641
1642    pub fn new_from_entry(key: &PolicyID, value: &MintAssets) -> Self {
1643        let mut m = Mint::new();
1644        m.insert(key, value);
1645        m
1646    }
1647
1648    pub fn len(&self) -> usize {
1649        self.0.len()
1650    }
1651
1652    //always returns None, because insert doesn't replace an old value
1653    pub fn insert(&mut self, key: &PolicyID, value: &MintAssets) -> Option<MintAssets> {
1654        self.0.push((key.clone(), value.clone()));
1655        None
1656    }
1657
1658    pub fn get(&self, key: &PolicyID) -> Option<MintsAssets> {
1659        let mints: Vec<MintAssets> = self
1660            .0
1661            .iter()
1662            .filter(|(k, _)| k.eq(key))
1663            .map(|(_k, v)| v.clone())
1664            .collect();
1665        if mints.is_empty() {
1666            None
1667        } else {
1668            Some(MintsAssets(mints))
1669        }
1670    }
1671
1672    pub fn keys(&self) -> PolicyIDs {
1673        ScriptHashes(
1674            self.0
1675                .iter()
1676                .map(|(k, _)| k.clone())
1677                .collect::<Vec<ScriptHash>>(),
1678        )
1679    }
1680
1681    fn as_multiasset(&self, is_positive: bool) -> Result<MultiAsset, JsError> {
1682        let mut ma = MultiAsset::new();
1683        for (policy_id, mint_assets) in &self.0 {
1684            let mut assets = Assets::new();
1685            for (asset_name, amount) in &mint_assets.0 {
1686                if amount.is_positive() != is_positive {
1687                    continue;
1688                }
1689                // Conway CDDL constrains mint amounts to `nonzero_int64`, but the
1690                // CBOR deserializer is permissive and accepts the full int range
1691                // [-2^64, 2^64-1]. The single value -2^64 has |x| = 2^64, which
1692                // cannot be represented in a u64-backed MultiAsset, so surface it
1693                // as an error rather than silently dropping the entry.
1694                let value = match is_positive {
1695                    true => amount.as_positive(),
1696                    false => amount.as_negative(),
1697                }
1698                .ok_or_else(|| {
1699                    JsError::from_str(&format!(
1700                        "Mint amount {} for policy {} does not fit a u64 MultiAsset value",
1701                        amount.0, policy_id
1702                    ))
1703                })?;
1704                assets.insert(asset_name, &value);
1705            }
1706            if !assets.0.is_empty() {
1707                ma.insert(policy_id, &assets);
1708            }
1709        }
1710        Ok(ma)
1711    }
1712
1713    /// Returns the multiasset where only positive (minting) entries are present
1714    pub fn as_positive_multiasset(&self) -> Result<MultiAsset, JsError> {
1715        self.as_multiasset(true)
1716    }
1717
1718    /// Returns the multiasset where only negative (burning) entries are present
1719    pub fn as_negative_multiasset(&self) -> Result<MultiAsset, JsError> {
1720        self.as_multiasset(false)
1721    }
1722}
1723
1724#[wasm_bindgen]
1725#[derive(
1726    Clone,
1727    Copy,
1728    Debug,
1729    Eq,
1730    Ord,
1731    PartialEq,
1732    PartialOrd,
1733    serde::Serialize,
1734    serde::Deserialize,
1735    JsonSchema,
1736)]
1737pub enum NetworkIdKind {
1738    Testnet,
1739    Mainnet,
1740}
1741
1742#[wasm_bindgen]
1743#[derive(
1744    Clone,
1745    Copy,
1746    Debug,
1747    Eq,
1748    Ord,
1749    PartialEq,
1750    PartialOrd,
1751    serde::Serialize,
1752    serde::Deserialize,
1753    JsonSchema,
1754)]
1755pub struct NetworkId(NetworkIdKind);
1756
1757impl_to_from!(NetworkId);
1758
1759#[wasm_bindgen]
1760impl NetworkId {
1761    pub fn testnet() -> Self {
1762        Self(NetworkIdKind::Testnet)
1763    }
1764
1765    pub fn mainnet() -> Self {
1766        Self(NetworkIdKind::Mainnet)
1767    }
1768
1769    pub fn kind(&self) -> NetworkIdKind {
1770        self.0
1771    }
1772}
1773
1774impl From<&NativeScript> for Ed25519KeyHashes {
1775    fn from(script: &NativeScript) -> Self {
1776        match &script.0 {
1777            NativeScriptEnum::ScriptPubkey(spk) => {
1778                let mut set = Ed25519KeyHashes::new();
1779                set.add_move(spk.addr_keyhash());
1780                set
1781            }
1782            NativeScriptEnum::ScriptAll(all) => Ed25519KeyHashes::from(&all.native_scripts),
1783            NativeScriptEnum::ScriptAny(any) => Ed25519KeyHashes::from(&any.native_scripts),
1784            NativeScriptEnum::ScriptNOfK(ofk) => Ed25519KeyHashes::from(&ofk.native_scripts),
1785            _ => Ed25519KeyHashes::new(),
1786        }
1787    }
1788}