whisky_pallas/wrapper/transaction_body/
drep.rs1use bech32::Hrp;
2use pallas::crypto::hash::Hash;
3use pallas::ledger::primitives::conway::DRep as PallasDRep;
4use pallas::ledger::primitives::Fragment;
5use std::str::FromStr;
6use whisky_common::WError;
7
8pub enum DRepKind {
9 Key { addr_key_hash: String },
10 Script { script_hash: String },
11 Abstain,
12 NoConfidence,
13}
14
15#[derive(Debug, PartialEq, Eq, Clone)]
16pub struct DRep {
17 pub inner: PallasDRep,
18}
19
20impl DRep {
21 pub fn new(drep: DRepKind) -> Result<Self, WError> {
22 let pallas_drep = match drep {
23 DRepKind::Key { addr_key_hash } => {
24 let key_hash = Hash::<28>::from_str(&addr_key_hash)
25 .map_err(|e| WError::new("DRep - Invalid key hash length", &e.to_string()))?;
26 PallasDRep::Key(key_hash)
27 }
28
29 DRepKind::Script { script_hash } => {
30 let script_hash = Hash::<28>::from_str(&script_hash).map_err(|e| {
31 WError::new("DRep - Invalid script hash length", &e.to_string())
32 })?;
33 PallasDRep::Script(script_hash)
34 }
35
36 DRepKind::Abstain => PallasDRep::Abstain,
37 DRepKind::NoConfidence => PallasDRep::NoConfidence,
38 };
39
40 Ok(Self { inner: pallas_drep })
41 }
42
43 pub fn from_bech32(bech32_str: &str) -> Result<Self, WError> {
44 let (hrp, data) = bech32::decode(bech32_str)
45 .map_err(|e| WError::new("DRep - Bech32 decode error", &e.to_string()))?;
46 if data.len() == 28 {
48 return match hrp.as_str() {
49 "drep_vkh" => Ok(Self {
50 inner: PallasDRep::Key(Hash::<28>::from(&data[..])),
51 }),
52 "drep" => Ok(Self {
53 inner: PallasDRep::Key(Hash::<28>::from(&data[..])),
54 }),
55 "drep_script" => Ok(Self {
56 inner: PallasDRep::Script(Hash::<28>::from(&data[..])),
57 }),
58 _ => Err(WError::new("DRep - Bech32 decode error", "Invalid HRP")),
59 };
60 } else {
61 let header_byte = data
63 .first()
64 .ok_or_else(|| WError::new("DRep - Bech32 decode error", "Empty data part"))?;
65
66 if header_byte >> 4 != 0b0010 {
68 return Err(WError::new(
69 "DRep - Bech32 decode error",
70 "Invalid DRep header byte",
71 ));
72 } else {
73 let is_script_hash = (header_byte & 0b0000_1111) == 0b0011;
75 if is_script_hash {
76 let script_hash = Hash::<28>::from(&data[1..]);
77 Ok(Self {
78 inner: PallasDRep::Script(script_hash),
79 })
80 } else {
81 let key_hash = Hash::<28>::from(&data[1..]);
82 Ok(Self {
83 inner: PallasDRep::Key(key_hash),
84 })
85 }
86 }
87 }
88 }
89
90 pub fn to_bech32_cip129(&self) -> Result<String, WError> {
91 let data: Vec<u8> = match &self.inner {
92 PallasDRep::Key(key_hash) => {
93 let mut d = vec![0b0010_0010]; d.extend_from_slice(key_hash.as_ref());
95 d
96 }
97 PallasDRep::Script(script_hash) => {
98 let mut d = vec![0b0010_0011]; d.extend_from_slice(script_hash.as_ref());
100 d
101 }
102 PallasDRep::Abstain => {
103 return Err(WError::new(
104 "DRep - Bech32 encode error",
105 "Cannot encode Abstain DRep to bech32",
106 ))
107 }
108 PallasDRep::NoConfidence => {
109 return Err(WError::new(
110 "DRep - Bech32 encode error",
111 "Cannot encode NoConfidence DRep to bech32",
112 ))
113 }
114 };
115
116 let bech32_str = bech32::encode::<bech32::Bech32>(Hrp::parse("drep").unwrap(), &data)
117 .map_err(|e| WError::new("DRep - Bech32 encode error", &e.to_string()))?;
118 Ok(bech32_str)
119 }
120
121 pub fn encode(&self) -> Result<String, WError> {
122 let encoded_fragment = self
123 .inner
124 .encode_fragment()
125 .map_err(|e| WError::new("DRep - Fragment encode error", &e.to_string()))?;
126 Ok(hex::encode(encoded_fragment))
127 }
128
129 pub fn decode_bytes(bytes: &[u8]) -> Result<Self, WError> {
130 let inner = PallasDRep::decode_fragment(&bytes)
131 .map_err(|e| WError::new("DRep - Fragment decode error", &e.to_string()))?;
132 Ok(Self { inner })
133 }
134}