whisky_pallas/wrapper/transaction_body/
reward_account.rs1use std::str::FromStr;
2
3use pallas::{
4 codec::utils::Bytes,
5 ledger::primitives::{
6 conway::RewardAccount as PallasRewardAccount, Fragment,
7 StakeCredential as PallasStakeCredential,
8 },
9};
10use pallas_crypto::hash::Hash;
11use whisky_common::WError;
12
13use crate::wrapper::transaction_body::StakeCredential;
14
15#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)]
16pub struct RewardAccount {
17 pub inner: PallasRewardAccount,
18}
19
20impl RewardAccount {
21 pub fn new(reward_account: String) -> Result<Self, WError> {
22 let inner = Bytes::from_str(&reward_account)
23 .map_err(|e| WError::new("RewardAccount - Invalid reward account", &e.to_string()))?;
24 Ok(Self { inner })
25 }
26
27 pub fn from_bech32(bech32_str: &str) -> Result<Self, WError> {
28 let (_hrp, data) = bech32::decode(bech32_str)
29 .map_err(|e| WError::new("Bech32 decode error", &format!("{}", e)))?;
30
31 Ok(Self {
32 inner: Bytes::from(data),
33 })
34 }
35
36 pub fn to_bech32(&self) -> Result<String, WError> {
37 let bytes = self.inner.to_vec();
38 let header_byte = bytes.first().ok_or_else(|| {
39 WError::new("StakeCredential - Bech32 decode error", "Empty data part")
40 })?;
41 if header_byte >> 5 != 0b111 {
43 return Err(WError::new(
44 "StakeCredential - Bech32 decode error",
45 "Invalid StakeCredential header byte",
46 ));
47 } else {
48 let hrp = if header_byte & 0b1 == 0 {
50 "stake_test"
51 } else {
52 "stake"
53 };
54 let bech32_str =
55 bech32::encode::<bech32::Bech32>(bech32::Hrp::parse(hrp).unwrap(), &bytes)
56 .map_err(|e| WError::new("Bech32 encode error", &format!("{}", e)))?;
57 Ok(bech32_str)
58 }
59 }
60
61 pub fn from_bytes(bytes: &[u8]) -> Result<Self, WError> {
62 let inner = Bytes::from(bytes.to_vec());
63 Ok(Self { inner })
64 }
65
66 pub fn to_stake_cred(&self) -> Result<StakeCredential, WError> {
67 let bytes = self.inner.to_vec();
68 let header_byte = bytes.first().ok_or_else(|| {
69 WError::new("StakeCredential - Bech32 decode error", "Empty data part")
70 })?;
71
72 if header_byte >> 5 != 0b111 {
74 return Err(WError::new(
75 "StakeCredential - Bech32 decode error",
76 "Invalid StakeCredential header byte",
77 ));
78 } else {
79 let is_script_hash = (header_byte >> 4) & 0b1 == 1;
81 if is_script_hash {
82 Ok(StakeCredential {
83 inner: PallasStakeCredential::ScriptHash(Hash::from(&bytes[1..])),
84 })
85 } else {
86 Ok(StakeCredential {
87 inner: PallasStakeCredential::AddrKeyhash(Hash::from(&bytes[1..])),
88 })
89 }
90 }
91 }
92
93 pub fn encode(&self) -> Result<String, WError> {
94 let encoded_fragment = self
95 .inner
96 .encode_fragment()
97 .map_err(|e| WError::new("RewardAccount - Fragment encode error", &e.to_string()))?;
98 Ok(hex::encode(encoded_fragment))
99 }
100
101 pub fn decode_bytes(bytes: &[u8]) -> Result<Self, WError> {
102 let inner = PallasRewardAccount::decode_fragment(&bytes)
103 .map_err(|e| WError::new("RewardAccount - Fragment decode error", &e.to_string()))?;
104 Ok(Self { inner })
105 }
106}