cardano_serialization_lib/builders/
certificates_builder.rs1use hashlink::LinkedHashMap;
2use crate::*;
3
4#[wasm_bindgen]
5#[derive(Clone, Debug)]
6pub struct CertificatesBuilder {
7 certs: LinkedHashMap<Certificate, Option<ScriptWitnessType>>,
8}
9
10#[wasm_bindgen]
11impl CertificatesBuilder {
12 pub fn new() -> Self {
13 Self { certs: LinkedHashMap::new() }
14 }
15
16 pub fn add(&mut self, cert: &Certificate) -> Result<(), JsError> {
17 if cert.has_required_script_witness() {
18 return Err(JsError::from_str(
19 "Your certificate has a required script witness.\
20 Please use .add_with_plutus_witness or .add_with_native_script instead.",
21 ));
22 }
23
24 if self.certs.contains_key(cert) {
25 return Err(JsError::from_str("Certificate already exists"));
26 }
27
28 self.certs.insert(cert.clone(), None);
29 Ok(())
30 }
31
32 pub fn add_with_plutus_witness(
33 &mut self,
34 cert: &Certificate,
35 witness: &PlutusWitness,
36 ) -> Result<(), JsError> {
37 if !cert.has_required_script_witness() {
38 return Err(JsError::from_str(
39 "Your certificate does not have a required script witness.\
40 Please use .add instead.",
41 ));
42 }
43
44 if self.certs.contains_key(cert) {
45 return Err(JsError::from_str("Certificate already exists"));
46 }
47
48 self.certs.insert(
49 cert.clone(),
50 Some(ScriptWitnessType::PlutusScriptWitness(witness.clone())),
51 );
52 Ok(())
53 }
54
55 pub fn add_with_native_script(
56 &mut self,
57 cert: &Certificate,
58 native_script_source: &NativeScriptSource,
59 ) -> Result<(), JsError> {
60 if !cert.has_required_script_witness() {
61 return Err(JsError::from_str(
62 "Your certificate does not have a required script witness.\
63 Please use .add instead.",
64 ));
65 }
66
67 if self.certs.contains_key(cert) {
68 return Err(JsError::from_str("Certificate already exists"));
69 }
70
71 self.certs.insert(
72 cert.clone(),
73 Some(ScriptWitnessType::NativeScriptWitness(
74 native_script_source.0.clone(),
75 )),
76 );
77 Ok(())
78 }
79
80 pub(crate) fn get_required_signers(&self) -> Ed25519KeyHashes {
81 let mut set = Ed25519KeyHashes::new();
82 for (cert, script_wit) in &self.certs {
83 let cert_req_signers = witness_keys_for_cert(&cert);
84 set.extend_move(cert_req_signers);
85 if let Some(script_wit) = script_wit {
86 if let Some(signers) = script_wit.get_required_signers() {
87 set.extend(&signers);
88 }
89 }
90 }
91 set
92 }
93
94 pub fn get_plutus_witnesses(&self) -> PlutusWitnesses {
95 let tag = RedeemerTag::new_cert();
96 let mut scripts = PlutusWitnesses::new();
97 for (i, (_, script_wit)) in self.certs.iter().enumerate() {
98 if let Some(ScriptWitnessType::PlutusScriptWitness(s)) = script_wit {
99 let index = BigNum::from(i);
100 scripts.add(&s.clone_with_redeemer_index_and_tag(&index, &tag));
101 }
102 }
103 scripts
104 }
105
106 pub fn get_ref_inputs(&self) -> TransactionInputs {
107 let mut inputs = Vec::new();
108 for (_, script_wit) in self.certs.iter() {
109 match script_wit {
110 Some(script_witness) => {
111 if let Some(input) = script_witness.get_script_ref_input() {
112 inputs.push(input);
113 }
114 if let Some(input) = script_witness.get_datum_ref_input() {
115 inputs.push(input);
116 }
117 }
118 None => {}
119 }
120 }
121 TransactionInputs::from_vec(inputs)
122 }
123
124 pub fn get_native_scripts(&self) -> NativeScripts {
125 let mut scripts = NativeScripts::new();
126 for (_, script_wit) in self.certs.iter() {
127 if let Some(ScriptWitnessType::NativeScriptWitness(
128 NativeScriptSourceEnum::NativeScript(script, _),
129 )) = script_wit
130 {
131 scripts.add(script);
132 }
133 }
134 scripts
135 }
136
137 pub(crate) fn get_used_plutus_lang_versions(&self) -> BTreeSet<Language> {
138 let mut used_langs = BTreeSet::new();
139 for (_, script_wit) in &self.certs {
140 if let Some(ScriptWitnessType::PlutusScriptWitness(s)) = script_wit {
141 used_langs.insert(s.script.language().clone());
142 }
143 }
144 used_langs
145 }
146
147 #[allow(unused_variables)]
148 pub fn get_certificates_refund(
149 &self,
150 pool_deposit: &BigNum,
151 key_deposit: &BigNum,
152 ) -> Result<Value, JsError> {
153 let mut refund = Coin::zero();
154 for (cert, _) in &self.certs {
155 match &cert.0 {
156 CertificateEnum::StakeDeregistration(cert) => {
157 if let Some(coin) = cert.coin {
158 refund = refund.checked_add(&coin)?;
159 } else {
160 refund = refund.checked_add(&key_deposit)?;
161 }
162 }
163 CertificateEnum::DRepDeregistration(cert) => {
164 refund = refund.checked_add(&cert.coin)?;
165 }
166 _ => {}
167 }
168 }
169 Ok(Value::new(&refund))
170 }
171
172 pub fn get_certificates_deposit(
173 &self,
174 pool_deposit: &BigNum,
175 key_deposit: &BigNum,
176 ) -> Result<Coin, JsError> {
177 let mut deposit = Coin::zero();
178 for (cert, _) in &self.certs {
179 match &cert.0 {
180 CertificateEnum::PoolRegistration(_) => {
181 deposit = deposit.checked_add(&pool_deposit)?;
182 }
183 CertificateEnum::StakeRegistration(cert) => {
184 if let Some(coin) = cert.coin {
185 deposit = deposit.checked_add(&coin)?;
186 } else {
187 deposit = deposit.checked_add(&key_deposit)?;
188 }
189 }
190 CertificateEnum::DRepRegistration(cert) => {
191 deposit = deposit.checked_add(&cert.coin)?;
192 }
193 CertificateEnum::StakeRegistrationAndDelegation(cert) => {
194 deposit = deposit.checked_add(&cert.coin)?;
195 }
196 CertificateEnum::VoteRegistrationAndDelegation(cert) => {
197 deposit = deposit.checked_add(&cert.coin)?;
198 }
199 CertificateEnum::StakeVoteRegistrationAndDelegation(cert) => {
200 deposit = deposit.checked_add(&cert.coin)?;
201 }
202 _ => {}
203 }
204 }
205 Ok(deposit)
206 }
207
208 pub fn has_plutus_scripts(&self) -> bool {
209 for (_, script_wit) in &self.certs {
210 if let Some(ScriptWitnessType::PlutusScriptWitness(_)) = script_wit {
211 return true;
212 }
213 }
214 false
215 }
216
217 pub fn build(&self) -> Certificates {
218 let certs = self.certs.iter().map(|(c, _)| c.clone()).collect();
219 Certificates::from_vec(certs)
220 }
221
222 pub(crate) fn get_script_ref_inputs_with_size(
226 &self,
227 ) -> impl Iterator<Item = (&TransactionInput, usize)> {
228 self.certs.iter()
229 .filter_map(|(_, opt_wit)| opt_wit.as_ref())
230 .filter_map(|script_wit| {
231 script_wit.get_script_ref_input_with_size()
232 })
233 }
234}
235
236fn witness_keys_for_cert(cert_enum: &Certificate) -> RequiredSigners {
238 let mut set = RequiredSigners::new();
239 match &cert_enum.0 {
240 CertificateEnum::StakeRegistration(cert) => {
242 if cert.coin.is_some() {
243 if let Some(key) = cert.stake_credential().to_keyhash() {
244 set.add(&key);
245 }
246 }
247 }
248 CertificateEnum::StakeDeregistration(cert) => {
249 if let Some(key) = cert.stake_credential().to_keyhash() {
250 set.add(&key);
251 }
252 }
253 CertificateEnum::StakeDelegation(cert) => {
254 if let Some(key) = cert.stake_credential().to_keyhash() {
255 set.add(&key);
256 }
257 }
258 CertificateEnum::PoolRegistration(cert) => {
259 set.extend(&cert.pool_params().pool_owners());
260 set.add(&cert.pool_params().operator());
261 }
262 CertificateEnum::PoolRetirement(cert) => {
263 set.add(&cert.pool_keyhash());
264 }
265 CertificateEnum::GenesisKeyDelegation(cert) => {
266 set.add(&Ed25519KeyHash::from_bytes(cert.genesis_delegate_hash().to_bytes()).unwrap());
267 }
268 CertificateEnum::MoveInstantaneousRewardsCert(_cert) => {}
270 CertificateEnum::CommitteeHotAuth(cert) => {
271 if let CredType::Key(key_hash) = &cert.committee_cold_credential.0 {
272 set.add(key_hash);
273 }
274 }
275 CertificateEnum::CommitteeColdResign(cert) => {
276 if let CredType::Key(key_hash) = &cert.committee_cold_credential.0 {
277 set.add(key_hash);
278 }
279 }
280 CertificateEnum::DRepUpdate(cert) => {
281 if let CredType::Key(key_hash) = &cert.voting_credential.0 {
282 set.add(key_hash);
283 }
284 }
285 CertificateEnum::DRepRegistration(cert) => {
286 if let CredType::Key(key_hash) = &cert.voting_credential.0 {
287 set.add(key_hash);
288 }
289 }
290 CertificateEnum::DRepDeregistration(cert) => {
291 if let CredType::Key(key_hash) = &cert.voting_credential.0 {
292 set.add(key_hash);
293 }
294 }
295 CertificateEnum::StakeAndVoteDelegation(cert) => {
296 if let CredType::Key(key_hash) = &cert.stake_credential.0 {
297 set.add(key_hash);
298 }
299 }
300 CertificateEnum::VoteDelegation(cert) => {
301 if let CredType::Key(key_hash) = &cert.stake_credential.0 {
302 set.add(key_hash);
303 }
304 }
305 CertificateEnum::StakeRegistrationAndDelegation(cert) => {
306 if let CredType::Key(key_hash) = &cert.stake_credential.0 {
307 set.add(key_hash);
308 }
309 }
310 CertificateEnum::VoteRegistrationAndDelegation(cert) => {
311 if let CredType::Key(key_hash) = &cert.stake_credential.0 {
312 set.add(key_hash);
313 }
314 }
315 CertificateEnum::StakeVoteRegistrationAndDelegation(cert) => {
316 if let CredType::Key(key_hash) = &cert.stake_credential.0 {
317 set.add(key_hash);
318 }
319 }
320 }
321 set
322}