cml_chain/transaction/
utils.rs1use std::collections::BTreeSet;
2
3use crate::{
4 address::Address,
5 plutus::Language,
6 transaction::{DatumOption, ScriptRef, TransactionOutput},
7 Value,
8};
9use cml_crypto::{DatumHash, Ed25519KeyHash, TransactionHash};
10
11use super::{
12 AlonzoFormatTxOut, ConwayFormatTxOut, NativeScript, TransactionBody, TransactionWitnessSet,
13};
14
15impl TransactionBody {
16 pub fn hash(&self) -> TransactionHash {
17 crate::crypto::hash::hash_transaction(self)
18 }
19}
20
21impl TransactionOutput {
22 pub fn new(
23 address: Address,
24 amount: Value,
25 datum_option: Option<DatumOption>,
26 script_reference: Option<ScriptRef>,
27 ) -> Self {
28 match (datum_option, script_reference) {
29 (None, None) => Self::AlonzoFormatTxOut(AlonzoFormatTxOut::new(address, amount)),
30 (Some(DatumOption::Hash { datum_hash, .. }), None) => {
31 let mut tx_out = AlonzoFormatTxOut::new(address, amount);
32 tx_out.datum_hash = Some(datum_hash);
33 Self::AlonzoFormatTxOut(tx_out)
34 }
35 (datum, script_ref) => {
36 let mut tx_out = ConwayFormatTxOut::new(address, amount);
37 tx_out.datum_option = datum;
38 tx_out.script_reference = script_ref;
39 Self::ConwayFormatTxOut(tx_out)
40 }
41 }
42 }
43
44 pub fn address(&self) -> &Address {
45 match self {
46 Self::AlonzoFormatTxOut(tx_out) => &tx_out.address,
47 Self::ConwayFormatTxOut(tx_out) => &tx_out.address,
48 }
49 }
50
51 pub fn set_address(&mut self, new_address: Address) {
52 match self {
53 Self::AlonzoFormatTxOut(tx_out) => tx_out.address = new_address,
54 Self::ConwayFormatTxOut(tx_out) => tx_out.address = new_address,
55 }
56 }
57
58 pub fn amount(&self) -> &Value {
59 match self {
60 Self::AlonzoFormatTxOut(tx_out) => &tx_out.amount,
61 Self::ConwayFormatTxOut(tx_out) => &tx_out.amount,
62 }
63 }
64
65 pub fn set_amount(&mut self, amount: Value) {
66 match self {
67 Self::AlonzoFormatTxOut(tx_out) => tx_out.amount = amount,
68 Self::ConwayFormatTxOut(tx_out) => tx_out.amount = amount,
69 }
70 }
71
72 pub fn datum(&self) -> Option<DatumOption> {
73 match self {
74 Self::AlonzoFormatTxOut(tx_out) => tx_out
75 .datum_hash
76 .as_ref()
77 .map(|hash| DatumOption::new_hash(*hash)),
78 Self::ConwayFormatTxOut(tx_out) => tx_out.datum_option.clone(),
79 }
80 }
81
82 pub fn datum_hash(&self) -> Option<&DatumHash> {
86 match self {
87 Self::AlonzoFormatTxOut(tx_out) => tx_out.datum_hash.as_ref(),
88 Self::ConwayFormatTxOut(tx_out) => match &tx_out.datum_option {
89 Some(DatumOption::Hash { datum_hash, .. }) => Some(datum_hash),
90 _ => None,
91 },
92 }
93 }
94
95 pub fn script_ref(&self) -> Option<&ScriptRef> {
96 match self {
97 Self::AlonzoFormatTxOut(_) => None,
98 Self::ConwayFormatTxOut(tx_out) => tx_out.script_reference.as_ref(),
99 }
100 }
101}
102
103impl From<AlonzoFormatTxOut> for TransactionOutput {
104 fn from(tx_out: AlonzoFormatTxOut) -> Self {
105 Self::AlonzoFormatTxOut(tx_out)
106 }
107}
108
109impl From<ConwayFormatTxOut> for TransactionOutput {
110 fn from(tx_out: ConwayFormatTxOut) -> Self {
111 Self::ConwayFormatTxOut(tx_out)
112 }
113}
114
115pub type RequiredSignersSet = BTreeSet<Ed25519KeyHash>;
116
117impl From<&NativeScript> for RequiredSignersSet {
118 fn from(script: &NativeScript) -> Self {
119 fn from_scripts(scripts: &[NativeScript]) -> RequiredSignersSet {
120 scripts.iter().fold(BTreeSet::new(), |mut set, s| {
121 RequiredSignersSet::from(s).iter().for_each(|pk| {
122 set.insert(*pk);
123 });
124 set
125 })
126 }
127 match script {
128 NativeScript::ScriptPubkey(spk) => {
129 let mut set = BTreeSet::new();
130 set.insert(spk.ed25519_key_hash);
131 set
132 }
133 NativeScript::ScriptAll(all) => from_scripts(&all.native_scripts),
134 NativeScript::ScriptAny(any) => from_scripts(&any.native_scripts),
135 NativeScript::ScriptNOfK(ofk) => from_scripts(&ofk.native_scripts),
136 _ => BTreeSet::new(),
137 }
138 }
139}
140
141impl NativeScript {
142 pub fn get_required_signers(&self) -> Vec<Ed25519KeyHash> {
146 RequiredSignersSet::from(self).iter().cloned().collect()
147 }
148}
149
150impl TransactionWitnessSet {
151 pub fn add_all_witnesses(&mut self, other: Self) {
152 if let Some(other_vkeys) = other.vkeywitnesses {
154 if let Some(vkeys) = &mut self.vkeywitnesses {
155 vkeys.extend(Vec::from(other_vkeys));
156 } else {
157 self.vkeywitnesses = Some(other_vkeys);
158 }
159 }
160 if let Some(other_native_scripts) = other.native_scripts {
161 if let Some(scripts) = &mut self.native_scripts {
162 scripts.extend(Vec::from(other_native_scripts));
163 } else {
164 self.native_scripts = Some(other_native_scripts);
165 }
166 }
167 if let Some(other_bootstraps) = other.bootstrap_witnesses {
168 if let Some(bootstraps) = &mut self.bootstrap_witnesses {
169 bootstraps.extend(Vec::from(other_bootstraps));
170 } else {
171 self.bootstrap_witnesses = Some(other_bootstraps);
172 }
173 }
174 if let Some(other_plutus_v1_scripts) = other.plutus_v1_scripts {
175 if let Some(scripts) = &mut self.plutus_v1_scripts {
176 scripts.extend(Vec::from(other_plutus_v1_scripts));
177 } else {
178 self.plutus_v1_scripts = Some(other_plutus_v1_scripts);
179 }
180 }
181 if let Some(other_plutus_v2_scripts) = other.plutus_v2_scripts {
182 if let Some(scripts) = &mut self.plutus_v2_scripts {
183 scripts.extend(Vec::from(other_plutus_v2_scripts));
184 } else {
185 self.plutus_v2_scripts = Some(other_plutus_v2_scripts);
186 }
187 }
188 if let Some(other_plutus_v3_scripts) = other.plutus_v3_scripts {
189 if let Some(scripts) = &mut self.plutus_v3_scripts {
190 scripts.extend(Vec::from(other_plutus_v3_scripts));
191 } else {
192 self.plutus_v3_scripts = Some(other_plutus_v3_scripts);
193 }
194 }
195 if let Some(other_plutus_datums) = other.plutus_datums {
196 if let Some(datums) = &mut self.plutus_datums {
197 datums.extend(Vec::from(other_plutus_datums));
198 } else {
199 self.plutus_datums = Some(other_plutus_datums);
200 }
201 }
202 if let Some(other_redeemers) = other.redeemers {
203 if let Some(redeemers) = &mut self.redeemers {
204 redeemers.extend(other_redeemers);
205 } else {
206 self.redeemers = Some(other_redeemers);
207 }
208 }
209 }
210
211 pub fn languages(&self) -> Vec<Language> {
212 let mut used_langs = vec![];
213 if self.plutus_v1_scripts.is_some() {
214 used_langs.push(Language::PlutusV1);
215 }
216 if self.plutus_v2_scripts.is_some() {
217 used_langs.push(Language::PlutusV2);
218 }
219 if self.plutus_v3_scripts.is_some() {
220 used_langs.push(Language::PlutusV3);
221 }
222 used_langs
223 }
224}