1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use cardano_serialization_lib::{self as csl};
4use whisky_common::{
5 Anchor, Certificate, CertificateType, CommitteeColdResign, CommitteeHotAuth, DRep,
6 DRepDeregistration, DRepRegistration, DRepUpdate, DelegateStake, DeregisterStake,
7 MultiHostName, PoolMetadata, PoolParams, RegisterPool, RegisterStake, Relay, RetirePool,
8 ScriptCertificate, ScriptSource, SimpleScriptCertificate, SimpleScriptSource, SingleHostAddr,
9 SingleHostName, StakeAndVoteDelegation, StakeRegistrationAndDelegation,
10 StakeVoteRegistrationAndDelegation, VoteDelegation, VoteRegistrationAndDelegation, WError,
11};
12
13use crate::tx_parser::context::{RedeemerIndex, Script};
14
15use super::CSLParser;
16
17impl CSLParser {
18 pub fn get_certificates(&self) -> &Vec<Certificate> {
19 &self.tx_body.certificates
20 }
21
22 pub(super) fn extract_certificates(&mut self) -> Result<(), WError> {
23 let certs = self.csl_tx_body.certs();
24 if certs.is_none() {
25 return Ok(());
26 }
27
28 let certs = certs.unwrap();
29 let mut result = Vec::new();
30 let len = certs.len();
31
32 for i in 0..len {
33 let cert = certs.get(i);
34
35 let script_hash = get_script_credential_from_cert(&cert);
36 let script_witness = script_hash
37 .map(|sh| self.context.script_witness.scripts.get(&sh))
38 .flatten()
39 .cloned();
40 let redeemer = self
41 .context
42 .script_witness
43 .redeemers
44 .get(&RedeemerIndex::Cert(i))
45 .cloned();
46 let certificate_type =
47 csl_cert_to_certificate_type(&cert, &csl::NetworkInfo::mainnet())?;
48 if let Some(certificate_type) = certificate_type {
49 if let Some(script_witness) = script_witness {
50 match script_witness {
51 Script::ProvidedNative(native_script) => {
52 result.push(Certificate::SimpleScriptCertificate(
53 SimpleScriptCertificate {
54 cert: certificate_type,
55 simple_script_source: Some(
56 SimpleScriptSource::ProvidedSimpleScriptSource(
57 native_script.clone(),
58 ),
59 ),
60 },
61 ));
62 }
63 Script::ProvidedPlutus(plutus_script) => {
64 result.push(Certificate::ScriptCertificate(ScriptCertificate {
65 cert: certificate_type,
66 script_source: Some(ScriptSource::ProvidedScriptSource(
67 plutus_script,
68 )),
69 redeemer,
70 }));
71 }
72 Script::ReferencedNative(inline_script) => {
73 result.push(Certificate::SimpleScriptCertificate(
74 SimpleScriptCertificate {
75 cert: certificate_type,
76 simple_script_source: Some(
77 SimpleScriptSource::InlineSimpleScriptSource(
78 inline_script.clone(),
79 ),
80 ),
81 },
82 ));
83 }
84 Script::ReferencedPlutus(inline_script) => {
85 result.push(Certificate::ScriptCertificate(ScriptCertificate {
86 cert: certificate_type,
87 script_source: Some(ScriptSource::InlineScriptSource(
88 inline_script,
89 )),
90 redeemer,
91 }));
92 }
93 }
94 } else {
95 result.push(Certificate::BasicCertificate(certificate_type));
96 }
97 };
98 }
99 self.tx_body.certificates = result;
100 Ok(())
101 }
102}
103
104fn get_script_credential_from_cert(cert: &csl::Certificate) -> Option<csl::ScriptHash> {
105 match cert.kind() {
106 csl::CertificateKind::StakeRegistration => cert
107 .as_stake_registration()
108 .map(|reg| reg.stake_credential())
109 .map(|cred| cred.to_scripthash())
110 .flatten(),
111 csl::CertificateKind::StakeDeregistration => cert
112 .as_stake_deregistration()
113 .map(|dereg| dereg.stake_credential())
114 .map(|cred| cred.to_scripthash())
115 .flatten(),
116 csl::CertificateKind::StakeDelegation => cert
117 .as_stake_delegation()
118 .map(|deleg| deleg.stake_credential())
119 .map(|cred| cred.to_scripthash())
120 .flatten(),
121 csl::CertificateKind::StakeAndVoteDelegation => cert
122 .as_stake_and_vote_delegation()
123 .map(|deleg| deleg.stake_credential())
124 .map(|cred| cred.to_scripthash())
125 .flatten(),
126 csl::CertificateKind::StakeRegistrationAndDelegation => cert
127 .as_stake_registration_and_delegation()
128 .map(|reg| reg.stake_credential())
129 .map(|cred| cred.to_scripthash())
130 .flatten(),
131 csl::CertificateKind::StakeVoteRegistrationAndDelegation => cert
132 .as_stake_vote_registration_and_delegation()
133 .map(|reg| reg.stake_credential())
134 .map(|cred| cred.to_scripthash())
135 .flatten(),
136 csl::CertificateKind::CommitteeHotAuth => cert
137 .as_committee_hot_auth()
138 .map(|auth| auth.committee_hot_credential())
139 .map(|cred| cred.to_scripthash())
140 .flatten(),
141 csl::CertificateKind::CommitteeColdResign => cert
142 .as_committee_cold_resign()
143 .map(|resign| resign.committee_cold_credential())
144 .map(|cred| cred.to_scripthash())
145 .flatten(),
146 csl::CertificateKind::DRepDeregistration => cert
147 .as_drep_deregistration()
148 .map(|dereg| dereg.voting_credential())
149 .map(|cred| cred.to_scripthash())
150 .flatten(),
151 csl::CertificateKind::DRepRegistration => cert
152 .as_drep_registration()
153 .map(|reg| reg.voting_credential())
154 .map(|cred| cred.to_scripthash())
155 .flatten(),
156 csl::CertificateKind::DRepUpdate => cert
157 .as_drep_update()
158 .map(|update| update.voting_credential())
159 .map(|cred| cred.to_scripthash())
160 .flatten(),
161 csl::CertificateKind::VoteDelegation => cert
162 .as_vote_delegation()
163 .map(|deleg| deleg.stake_credential())
164 .map(|cred| cred.to_scripthash())
165 .flatten(),
166 csl::CertificateKind::VoteRegistrationAndDelegation => cert
167 .as_vote_registration_and_delegation()
168 .map(|reg| reg.stake_credential())
169 .map(|cred| cred.to_scripthash())
170 .flatten(),
171 csl::CertificateKind::PoolRegistration => None,
172 csl::CertificateKind::PoolRetirement => None,
173 csl::CertificateKind::GenesisKeyDelegation => None,
174 csl::CertificateKind::MoveInstantaneousRewardsCert => None,
175 }
176}
177
178fn csl_drep_to_drep(csl_drep: &csl::DRep) -> Result<DRep, WError> {
179 match csl_drep.kind() {
180 csl::DRepKind::KeyHash => {
181 let drep_id = csl_drep.to_bech32(true).map_err(|e| {
182 WError::new(
183 "csl_drep_to_drep",
184 &format!("Failed to convert drep to bech32: {:?}", e),
185 )
186 })?;
187 Ok(DRep::DRepId(drep_id))
188 }
189 csl::DRepKind::AlwaysAbstain => Ok(DRep::AlwaysAbstain),
190 csl::DRepKind::AlwaysNoConfidence => Ok(DRep::AlwaysNoConfidence),
191 csl::DRepKind::ScriptHash => {
192 let drep_id = csl_drep.to_bech32(true).map_err(|e| {
193 WError::new(
194 "csl_drep_to_drep",
195 &format!("Failed to convert drep to bech32: {:?}", e),
196 )
197 })?;
198 Ok(DRep::DRepId(drep_id))
199 }
200 }
201}
202
203fn csl_cert_to_certificate_type(
204 cert: &csl::Certificate,
205 network_id: &csl::NetworkInfo,
206) -> Result<Option<CertificateType>, WError> {
207 match cert.kind() {
208 csl::CertificateKind::StakeRegistration => {
209 let reg = cert.as_stake_registration().ok_or_else(|| {
210 WError::new(
211 "csl_cert_to_certificate_type",
212 "Failed to get stake registration",
213 )
214 })?;
215 let stake_cred = reg.stake_credential();
216 let stake_key_address = csl::RewardAddress::new(network_id.network_id(), &stake_cred)
217 .to_address()
218 .to_bech32(None)
219 .map_err(|e| {
220 WError::new(
221 "csl_cert_to_certificate_type",
222 &format!("Failed to convert address to bech32: {:?}", e),
223 )
224 })?;
225 Ok(Some(CertificateType::RegisterStake(RegisterStake {
226 stake_key_address,
227 coin: 0,
228 })))
229 }
230 csl::CertificateKind::StakeDeregistration => {
231 let dereg = cert.as_stake_deregistration().ok_or_else(|| {
232 WError::new(
233 "csl_cert_to_certificate_type",
234 "Failed to get stake deregistration",
235 )
236 })?;
237 let stake_cred = dereg.stake_credential();
238 let stake_key_address = csl::RewardAddress::new(network_id.network_id(), &stake_cred)
239 .to_address()
240 .to_bech32(None)
241 .map_err(|e| {
242 WError::new(
243 "csl_cert_to_certificate_type",
244 &format!("Failed to convert address to bech32: {:?}", e),
245 )
246 })?;
247 Ok(Some(CertificateType::DeregisterStake(DeregisterStake {
248 stake_key_address,
249 })))
250 }
251 csl::CertificateKind::StakeDelegation => {
252 let deleg = cert.as_stake_delegation().ok_or_else(|| {
253 WError::new(
254 "csl_cert_to_certificate_type",
255 "Failed to get stake delegation",
256 )
257 })?;
258 let stake_cred = deleg.stake_credential();
259 let stake_key_address = csl::RewardAddress::new(network_id.network_id(), &stake_cred)
260 .to_address()
261 .to_bech32(None)
262 .map_err(|e| {
263 WError::new(
264 "csl_cert_to_certificate_type",
265 &format!("Failed to convert address to bech32: {:?}", e),
266 )
267 })?;
268 let pool_id = deleg.pool_keyhash().to_hex();
269 Ok(Some(CertificateType::DelegateStake(DelegateStake {
270 stake_key_address,
271 pool_id,
272 })))
273 }
274 csl::CertificateKind::PoolRegistration => {
275 let pool_reg = cert.as_pool_registration().ok_or_else(|| {
276 WError::new(
277 "csl_cert_to_certificate_type",
278 "Failed to get pool registration",
279 )
280 })?;
281 let pool_params = pool_reg.pool_params();
282 let mapped_pool_params = csl_pool_params_to_pool_params(&pool_params)?;
283 Ok(Some(CertificateType::RegisterPool(RegisterPool {
284 pool_params: mapped_pool_params,
285 })))
286 }
287 csl::CertificateKind::PoolRetirement => {
288 let pool_ret = cert.as_pool_retirement().ok_or_else(|| {
289 WError::new(
290 "csl_cert_to_certificate_type",
291 "Failed to get pool retirement",
292 )
293 })?;
294 let pool_id = pool_ret.pool_keyhash().to_hex();
295 let epoch = pool_ret.epoch();
296 Ok(Some(CertificateType::RetirePool(RetirePool {
297 pool_id,
298 epoch,
299 })))
300 }
301 csl::CertificateKind::GenesisKeyDelegation => Ok(None),
302 csl::CertificateKind::MoveInstantaneousRewardsCert => Ok(None),
303 csl::CertificateKind::CommitteeHotAuth => {
304 let committee_hot_auth = cert.as_committee_hot_auth().ok_or_else(|| {
305 WError::new(
306 "csl_cert_to_certificate_type",
307 "Failed to get committee hot auth",
308 )
309 })?;
310 let committee_cold_credential = committee_hot_auth.committee_cold_credential().to_hex();
311 let committee_hot_credential = committee_hot_auth.committee_hot_credential().to_hex();
312 Ok(Some(CertificateType::CommitteeHotAuth(CommitteeHotAuth {
313 committee_cold_key_address: committee_cold_credential,
314 committee_hot_key_address: committee_hot_credential,
315 })))
316 }
317 csl::CertificateKind::CommitteeColdResign => {
318 let committee_cold_resign = cert.as_committee_cold_resign().ok_or_else(|| {
319 WError::new(
320 "csl_cert_to_certificate_type",
321 "Failed to get committee cold resign",
322 )
323 })?;
324 let committee_cold_credential =
325 committee_cold_resign.committee_cold_credential().to_hex();
326 let anchor = committee_cold_resign.anchor().map(|a| Anchor {
327 anchor_url: a.url().url(),
328 anchor_data_hash: a.anchor_data_hash().to_hex(),
329 });
330 Ok(Some(CertificateType::CommitteeColdResign(
331 CommitteeColdResign {
332 committee_cold_key_address: committee_cold_credential,
333 anchor,
334 },
335 )))
336 }
337 csl::CertificateKind::DRepDeregistration => {
338 let drep_dereg = cert.as_drep_deregistration().ok_or_else(|| {
339 WError::new(
340 "csl_cert_to_certificate_type",
341 "Failed to get drep deregistration",
342 )
343 })?;
344 let drep = csl::DRep::new_from_credential(&drep_dereg.voting_credential());
345 let drep_id = drep.to_bech32(true).map_err(|e| {
346 WError::new(
347 "csl_cert_to_certificate_type",
348 &format!("Failed to convert drep to bech32: {:?}", e),
349 )
350 })?;
351 let coin = drep_dereg.coin().to_str().parse::<u64>().unwrap_or(0);
352 Ok(Some(CertificateType::DRepDeregistration(
353 DRepDeregistration { drep_id, coin },
354 )))
355 }
356 csl::CertificateKind::DRepRegistration => {
357 let drep_reg = cert.as_drep_registration().ok_or_else(|| {
358 WError::new(
359 "csl_cert_to_certificate_type",
360 "Failed to get drep registration",
361 )
362 })?;
363 let drep = csl::DRep::new_from_credential(&drep_reg.voting_credential());
364 let drep_id = drep.to_bech32(true).map_err(|e| {
365 WError::new(
366 "csl_cert_to_certificate_type",
367 &format!("Failed to convert drep to bech32: {:?}", e),
368 )
369 })?;
370 let coin = drep_reg.coin().to_str().parse::<u64>().unwrap_or(0);
371 let anchor = drep_reg.anchor().map(|a| Anchor {
372 anchor_url: a.url().url(),
373 anchor_data_hash: a.anchor_data_hash().to_hex(),
374 });
375 Ok(Some(CertificateType::DRepRegistration(DRepRegistration {
376 drep_id,
377 coin,
378 anchor,
379 })))
380 }
381 csl::CertificateKind::DRepUpdate => {
382 let drep_update = cert.as_drep_update().ok_or_else(|| {
383 WError::new("csl_cert_to_certificate_type", "Failed to get drep update")
384 })?;
385 let drep = csl::DRep::new_from_credential(&drep_update.voting_credential());
386 let drep_id = drep.to_bech32(true).map_err(|e| {
387 WError::new(
388 "csl_cert_to_certificate_type",
389 &format!("Failed to convert drep to bech32: {:?}", e),
390 )
391 })?;
392 let anchor = drep_update.anchor().map(|a| Anchor {
393 anchor_url: a.url().url(),
394 anchor_data_hash: a.anchor_data_hash().to_hex(),
395 });
396 Ok(Some(CertificateType::DRepUpdate(DRepUpdate {
397 drep_id,
398 anchor,
399 })))
400 }
401 csl::CertificateKind::VoteDelegation => {
402 let vote_deleg = cert.as_vote_delegation().ok_or_else(|| {
403 WError::new(
404 "csl_cert_to_certificate_type",
405 "Failed to get vote delegation",
406 )
407 })?;
408 let stake_cred = vote_deleg.stake_credential();
409 let stake_key_address = csl::RewardAddress::new(network_id.network_id(), &stake_cred)
410 .to_address()
411 .to_bech32(None)
412 .map_err(|e| {
413 WError::new(
414 "csl_cert_to_certificate_type",
415 &format!("Failed to convert address to bech32: {:?}", e),
416 )
417 })?;
418 let drep = csl_drep_to_drep(&vote_deleg.drep())?;
419 Ok(Some(CertificateType::VoteDelegation(VoteDelegation {
420 stake_key_address,
421 drep,
422 })))
423 }
424 csl::CertificateKind::StakeAndVoteDelegation => {
425 let stake_and_vote_deleg = cert.as_stake_and_vote_delegation().ok_or_else(|| {
426 WError::new(
427 "csl_cert_to_certificate_type",
428 "Failed to get stake and vote delegation",
429 )
430 })?;
431 let stake_key_address = csl::RewardAddress::new(
432 network_id.network_id(),
433 &stake_and_vote_deleg.stake_credential(),
434 )
435 .to_address()
436 .to_bech32(None)
437 .map_err(|e| {
438 WError::new(
439 "csl_cert_to_certificate_type",
440 &format!("Failed to convert address to bech32: {:?}", e),
441 )
442 })?;
443 let pool_key_hash = stake_and_vote_deleg.pool_keyhash().to_hex();
444 let drep = csl_drep_to_drep(&stake_and_vote_deleg.drep())?;
445 Ok(Some(CertificateType::StakeAndVoteDelegation(
446 StakeAndVoteDelegation {
447 stake_key_address,
448 drep,
449 pool_key_hash,
450 },
451 )))
452 }
453 csl::CertificateKind::StakeRegistrationAndDelegation => {
454 let stake_reg_and_deleg =
455 cert.as_stake_registration_and_delegation().ok_or_else(|| {
456 WError::new(
457 "csl_cert_to_certificate_type",
458 "Failed to get stake registration and delegation",
459 )
460 })?;
461 let stake_key_address = csl::RewardAddress::new(
462 network_id.network_id(),
463 &stake_reg_and_deleg.stake_credential(),
464 )
465 .to_address()
466 .to_bech32(None)
467 .map_err(|e| {
468 WError::new(
469 "csl_cert_to_certificate_type",
470 &format!("Failed to convert address to bech32: {:?}", e),
471 )
472 })?;
473 let pool_key_hash = stake_reg_and_deleg.pool_keyhash().to_hex();
474 let coin = stake_reg_and_deleg
475 .coin()
476 .to_str()
477 .parse::<u64>()
478 .unwrap_or(0);
479 Ok(Some(CertificateType::StakeRegistrationAndDelegation(
480 StakeRegistrationAndDelegation {
481 stake_key_address,
482 pool_key_hash,
483 coin,
484 },
485 )))
486 }
487 csl::CertificateKind::StakeVoteRegistrationAndDelegation => {
488 let stake_vote_reg_and_deleg = cert
489 .as_stake_vote_registration_and_delegation()
490 .ok_or_else(|| {
491 WError::new(
492 "csl_cert_to_certificate_type",
493 "Failed to get stake vote registration and delegation",
494 )
495 })?;
496 let stake_key_address = csl::RewardAddress::new(
497 network_id.network_id(),
498 &stake_vote_reg_and_deleg.stake_credential(),
499 )
500 .to_address()
501 .to_bech32(None)
502 .map_err(|e| {
503 WError::new(
504 "csl_cert_to_certificate_type",
505 &format!("Failed to convert address to bech32: {:?}", e),
506 )
507 })?;
508 let pool_key_hash = stake_vote_reg_and_deleg.pool_keyhash().to_hex();
509 let coin = stake_vote_reg_and_deleg
510 .coin()
511 .to_str()
512 .parse::<u64>()
513 .unwrap_or(0);
514 let drep = csl_drep_to_drep(&stake_vote_reg_and_deleg.drep())?;
515 Ok(Some(CertificateType::StakeVoteRegistrationAndDelegation(
516 StakeVoteRegistrationAndDelegation {
517 stake_key_address,
518 pool_key_hash,
519 coin,
520 drep,
521 },
522 )))
523 }
524 csl::CertificateKind::VoteRegistrationAndDelegation => {
525 let vote_reg_and_deleg =
526 cert.as_vote_registration_and_delegation().ok_or_else(|| {
527 WError::new(
528 "csl_cert_to_certificate_type",
529 "Failed to get vote registration and delegation",
530 )
531 })?;
532 let stake_key_address = csl::RewardAddress::new(
533 network_id.network_id(),
534 &vote_reg_and_deleg.stake_credential(),
535 )
536 .to_address()
537 .to_bech32(None)
538 .map_err(|e| {
539 WError::new(
540 "csl_cert_to_certificate_type",
541 &format!("Failed to convert address to bech32: {:?}", e),
542 )
543 })?;
544 let drep = csl_drep_to_drep(&vote_reg_and_deleg.drep())?;
545 let coin = vote_reg_and_deleg
546 .coin()
547 .to_str()
548 .parse::<u64>()
549 .unwrap_or(0);
550 Ok(Some(CertificateType::VoteRegistrationAndDelegation(
551 VoteRegistrationAndDelegation {
552 stake_key_address,
553 drep,
554 coin,
555 },
556 )))
557 }
558 }
559}
560
561pub fn csl_pool_params_to_pool_params(pool_params: &csl::PoolParams) -> Result<PoolParams, WError> {
562 let vrf_key_hash = pool_params.vrf_keyhash().to_hex();
563 let operator = pool_params.operator().to_hex();
564 let pledge = pool_params.pledge().to_str();
565 let cost = pool_params.cost().to_str();
566 let margin = (
567 pool_params
568 .margin()
569 .numerator()
570 .to_str()
571 .parse::<u64>()
572 .unwrap_or(0),
573 pool_params
574 .margin()
575 .denominator()
576 .to_str()
577 .parse::<u64>()
578 .unwrap_or(1),
579 );
580 let reward_address = pool_params
581 .reward_account()
582 .to_address()
583 .to_bech32(None)
584 .map_err(|e| {
585 WError::new(
586 "csl_pool_params_to_pool_params",
587 &format!("Failed to convert reward address to bech32: {:?}", e),
588 )
589 })?;
590
591 let pool_owners = (0..pool_params.pool_owners().len())
592 .map(|i| pool_params.pool_owners().get(i).to_hex())
593 .collect();
594
595 let mut relays = Vec::new();
596 let csl_relays = pool_params.relays();
597 let relays_len = csl_relays.len();
598 for i in 0..relays_len {
599 let relay = csl_relays.get(i);
600 let relay = csl_relay_to_relay(&relay)?;
601 relays.push(relay);
602 }
603
604 let metadata = pool_params.pool_metadata().map(|metadata| PoolMetadata {
605 url: metadata.url().url(),
606 hash: metadata.pool_metadata_hash().to_hex(),
607 });
608
609 Ok(PoolParams {
610 vrf_key_hash,
611 operator,
612 pledge,
613 cost,
614 margin,
615 relays,
616 owners: pool_owners,
617 reward_address,
618 metadata,
619 })
620}
621
622pub fn csl_relay_to_relay(relay: &csl::Relay) -> Result<Relay, WError> {
623 match relay.kind() {
624 csl::RelayKind::SingleHostAddr => {
625 let single_host_addr = relay.as_single_host_addr().ok_or_else(|| {
626 WError::new("csl_relay_to_relay", "Failed to get single host addr")
627 })?;
628 Ok(Relay::SingleHostAddr(SingleHostAddr {
629 ipv4: single_host_addr.ipv4().map(|ipv4| {
630 let octets = ipv4.ip();
631 let ipv4_bytes = <[u8; 4]>::try_from(&octets[..4]).unwrap_or([0, 0, 0, 0]);
632 Ipv4Addr::from(ipv4_bytes).to_string()
633 }),
634 ipv6: single_host_addr.ipv6().map(|ipv6| {
635 let octets = ipv6.ip();
636 let ipv6_bytes = <[u8; 16]>::try_from(&octets[..16]).unwrap_or([0; 16]);
637 Ipv6Addr::from(ipv6_bytes).to_string()
638 }),
639 port: single_host_addr.port(),
640 }))
641 }
642 csl::RelayKind::SingleHostName => {
643 let single_host_name = relay.as_single_host_name().ok_or_else(|| {
644 WError::new("csl_relay_to_relay", "Failed to get single host name")
645 })?;
646 Ok(Relay::SingleHostName(SingleHostName {
647 domain_name: single_host_name.dns_name().record(),
648 port: single_host_name.port(),
649 }))
650 }
651 csl::RelayKind::MultiHostName => {
652 let multi_host_name = relay.as_multi_host_name().ok_or_else(|| {
653 WError::new("csl_relay_to_relay", "Failed to get multi host name")
654 })?;
655 Ok(Relay::MultiHostName(MultiHostName {
656 domain_name: multi_host_name.dns_name().record(),
657 }))
658 }
659 }
660}