whisky_pallas/wrapper/transaction_body/
certificate.rs

1use std::str::FromStr;
2
3use pallas::{
4    codec::utils::Set,
5    ledger::primitives::{
6        conway::Certificate::{
7            self as PallasCertificate, PoolRegistration as PallasPoolRegistration,
8        },
9        Fragment,
10    },
11};
12use whisky_common::WError;
13
14use crate::wrapper::transaction_body::{
15    parse_rational_number, Anchor, DRep, PoolMetadata, Relay, RewardAccount, StakeCredential,
16};
17
18pub enum CertificateKind {
19    StakeRegistration {
20        stake_credential: StakeCredential,
21    },
22    StakeDeregistration {
23        stake_credential: StakeCredential,
24    },
25    StakeDelegation {
26        stake_credential: StakeCredential,
27        pool_key_hash: String,
28    },
29    PoolRegistration {
30        operator: String,    // pool key hash
31        vrf_keyhash: String, // vrf key hash
32        pledge: u64,
33        cost: u64,
34        margin: (u64, u64), // (nominator, denominator)
35        reward_account: RewardAccount,
36        pool_owners: Vec<String>, // set of pool owner addr key hashes
37        relays: Vec<Relay>,
38        pool_metadata: Option<PoolMetadata>, // Nullable PoolMetadata
39    },
40    PoolRetirement {
41        pool_key_hash: String,
42        epoch: u64,
43    },
44
45    Reg {
46        stake_credential: StakeCredential,
47        amount: u64,
48    },
49    UnReg {
50        stake_credential: StakeCredential,
51        amount: u64,
52    },
53    VoteDeleg {
54        stake_credential: StakeCredential,
55        drep: DRep,
56    },
57    StakeVoteDeleg {
58        stake_credential: StakeCredential,
59        pool_key_hash: String,
60        drep: DRep,
61    },
62    StakeRegDeleg {
63        stake_credential: StakeCredential,
64        pool_key_hash: String,
65        amount: u64,
66    },
67    VoteRegDeleg {
68        stake_credential: StakeCredential,
69        drep: DRep,
70        amount: u64,
71    },
72    StakeVoteRegDeleg {
73        stake_credential: StakeCredential,
74        pool_key_hash: String,
75        drep: DRep,
76        amount: u64,
77    },
78    AuthCommitteeHot {
79        committee_cold_cred: StakeCredential,
80        committee_hot_cred: StakeCredential,
81    },
82    ResignCommitteeCold {
83        committee_cold_cred: StakeCredential,
84        anchor: Option<Anchor>,
85    },
86    RegDRepCert {
87        drep_cred: StakeCredential,
88        amount: u64,
89        anchor: Option<Anchor>,
90    },
91    UnRegDRepCert {
92        drep_cred: StakeCredential,
93        amount: u64,
94    },
95    UpdateDRepCert {
96        drep_cred: StakeCredential,
97        anchor: Option<Anchor>,
98    },
99}
100
101#[derive(Debug, PartialEq, Eq, Clone)]
102pub struct Certificate {
103    pub inner: PallasCertificate,
104}
105
106impl Certificate {
107    pub fn new(certificate_kind: CertificateKind) -> Result<Self, WError> {
108        let pallas_certificate = match certificate_kind {
109            CertificateKind::StakeRegistration { stake_credential } => {
110                PallasCertificate::StakeRegistration(stake_credential.inner)
111            }
112            CertificateKind::StakeDeregistration { stake_credential } => {
113                PallasCertificate::StakeDeregistration(stake_credential.inner)
114            }
115            CertificateKind::StakeDelegation {
116                stake_credential,
117                pool_key_hash,
118            } => {
119                let pallas_pool_key_hash = pallas::ledger::primitives::Hash::<28>::from_str(
120                    &pool_key_hash,
121                )
122                .map_err(|_| {
123                    WError::new(
124                        "WhiskyPallas - Creating Certificate",
125                        "invalid pool key hash",
126                    )
127                })?;
128                PallasCertificate::StakeDelegation(stake_credential.inner, pallas_pool_key_hash)
129            }
130            CertificateKind::PoolRegistration {
131                operator,
132                vrf_keyhash,
133                pledge,
134                cost,
135                margin,
136                reward_account,
137                pool_owners,
138                relays,
139                pool_metadata,
140            } => {
141                let pallas_operator = pallas::ledger::primitives::Hash::<28>::from_str(&operator)
142                    .map_err(|_| {
143                    WError::new(
144                        "WhiskyPallas - Creating Certificate",
145                        "invalid operator pool key hash",
146                    )
147                })?;
148                let pallas_vrf_keyhash = pallas::ledger::primitives::Hash::<32>::from_str(
149                    &vrf_keyhash,
150                )
151                .map_err(|_| {
152                    WError::new(
153                        "WhiskyPallas - Creating Certificate",
154                        "invalid vrf key hash",
155                    )
156                })?;
157                let mut pallas_pool_owners_vec = Vec::new();
158                for owner in pool_owners {
159                    let pallas_owner = pallas::ledger::primitives::Hash::<28>::from_str(&owner)
160                        .map_err(|_| {
161                            WError::new(
162                                "WhiskyPallas - Creating Certificate",
163                                "invalid pool owner key hash",
164                            )
165                        })?;
166                    pallas_pool_owners_vec.push(pallas_owner);
167                }
168                let pallas_relays: Vec<pallas::ledger::primitives::conway::Relay> =
169                    relays.into_iter().map(|r| r.inner).collect();
170                let pallas_pool_metadata = match pool_metadata {
171                    Some(pm) => Some(pm.inner),
172                    None => None,
173                };
174                PallasPoolRegistration {
175                    operator: pallas_operator,
176                    vrf_keyhash: pallas_vrf_keyhash,
177                    pledge,
178                    cost,
179                    margin: parse_rational_number(margin),
180                    reward_account: reward_account.inner,
181                    pool_owners: Set::from(pallas_pool_owners_vec),
182                    relays: pallas_relays,
183                    pool_metadata: pallas_pool_metadata,
184                }
185            }
186            CertificateKind::PoolRetirement {
187                pool_key_hash,
188                epoch,
189            } => {
190                let pallas_pool_key_hash = pallas::ledger::primitives::Hash::<28>::from_str(
191                    &pool_key_hash,
192                )
193                .map_err(|_| {
194                    WError::new(
195                        "WhiskyPallas - Creating Certificate",
196                        "invalid pool key hash",
197                    )
198                })?;
199                PallasCertificate::PoolRetirement(pallas_pool_key_hash, epoch)
200            }
201            CertificateKind::Reg {
202                stake_credential,
203                amount,
204            } => PallasCertificate::Reg(stake_credential.inner, amount),
205            CertificateKind::UnReg {
206                stake_credential,
207                amount,
208            } => PallasCertificate::UnReg(stake_credential.inner, amount),
209            CertificateKind::VoteDeleg {
210                stake_credential,
211                drep,
212            } => PallasCertificate::VoteDeleg(stake_credential.inner, drep.inner),
213            CertificateKind::StakeVoteDeleg {
214                stake_credential,
215                pool_key_hash,
216                drep,
217            } => {
218                let pallas_pool_key_hash = pallas::ledger::primitives::Hash::<28>::from_str(
219                    &pool_key_hash,
220                )
221                .map_err(|_| {
222                    WError::new(
223                        "WhiskyPallas - Creating Certificate",
224                        "invalid pool key hash",
225                    )
226                })?;
227                PallasCertificate::StakeVoteDeleg(
228                    stake_credential.inner,
229                    pallas_pool_key_hash,
230                    drep.inner,
231                )
232            }
233            CertificateKind::StakeRegDeleg {
234                stake_credential,
235                pool_key_hash,
236                amount,
237            } => {
238                let pallas_pool_key_hash = pallas::ledger::primitives::Hash::<28>::from_str(
239                    &pool_key_hash,
240                )
241                .map_err(|_| {
242                    WError::new(
243                        "WhiskyPallas - Creating Certificate",
244                        "invalid pool key hash",
245                    )
246                })?;
247                PallasCertificate::StakeRegDeleg(
248                    stake_credential.inner,
249                    pallas_pool_key_hash,
250                    amount,
251                )
252            }
253            CertificateKind::VoteRegDeleg {
254                stake_credential,
255                drep,
256                amount,
257            } => PallasCertificate::VoteRegDeleg(stake_credential.inner, drep.inner, amount),
258            CertificateKind::StakeVoteRegDeleg {
259                stake_credential,
260                pool_key_hash,
261                drep,
262                amount,
263            } => {
264                let pallas_pool_key_hash = pallas::ledger::primitives::Hash::<28>::from_str(
265                    &pool_key_hash,
266                )
267                .map_err(|_| {
268                    WError::new(
269                        "WhiskyPallas - Creating Certificate",
270                        "invalid pool key hash",
271                    )
272                })?;
273                PallasCertificate::StakeVoteRegDeleg(
274                    stake_credential.inner,
275                    pallas_pool_key_hash,
276                    drep.inner,
277                    amount,
278                )
279            }
280            CertificateKind::AuthCommitteeHot {
281                committee_cold_cred,
282                committee_hot_cred,
283            } => PallasCertificate::AuthCommitteeHot(
284                committee_cold_cred.inner,
285                committee_hot_cred.inner,
286            ),
287            CertificateKind::ResignCommitteeCold {
288                committee_cold_cred,
289                anchor,
290            } => PallasCertificate::ResignCommitteeCold(
291                committee_cold_cred.inner,
292                anchor.map(|a| a.inner),
293            ),
294            CertificateKind::RegDRepCert {
295                drep_cred,
296                amount,
297                anchor,
298            } => PallasCertificate::RegDRepCert(drep_cred.inner, amount, anchor.map(|a| a.inner)),
299            CertificateKind::UnRegDRepCert { drep_cred, amount } => {
300                PallasCertificate::UnRegDRepCert(drep_cred.inner, amount)
301            }
302            CertificateKind::UpdateDRepCert { drep_cred, anchor } => {
303                PallasCertificate::UpdateDRepCert(drep_cred.inner, anchor.map(|a| a.inner))
304            }
305        };
306
307        Ok(Self {
308            inner: pallas_certificate,
309        })
310    }
311
312    pub fn encode(&self) -> String {
313        hex::encode(
314            self.inner
315                .encode_fragment()
316                .expect("encoding failed at Certificate"),
317        )
318    }
319
320    pub fn decode_bytes(bytes: &[u8]) -> Result<Self, String> {
321        let inner = PallasCertificate::decode_fragment(&bytes)
322            .map_err(|e| format!("Fragment decode error: {}", e.to_string()))?;
323        Ok(Self { inner })
324    }
325}