whisky_pallas/wrapper/transaction_body/
gov_action.rs1use std::{collections::BTreeMap, str::FromStr};
2
3use pallas::{
4 codec::utils::Set,
5 crypto::hash::Hash,
6 ledger::primitives::{
7 conway::GovAction as PallasGovAction, Fragment, StakeCredential as PallasStakeCredential,
8 },
9};
10
11use crate::wrapper::transaction_body::{
12 parse_rational_number, Constitution, GovActionId, ProtocolParamUpdate, RewardAccount,
13 StakeCredential,
14};
15
16pub enum GovActionKind {
17 ParameterChange {
18 gov_action_id: Option<GovActionId>,
19 protocol_param_update: ProtocolParamUpdate,
20 script_hash: Option<String>,
21 },
22 HardForkInitiation {
23 gov_action_id: Option<GovActionId>,
24 protocol_version: (u64, u64),
25 },
26 TreasuryWithdrawals {
27 withdrawals: Vec<(RewardAccount, u64)>,
28 script_hash: Option<String>,
29 },
30 NoConfidence {
31 gov_action_id: Option<GovActionId>,
32 },
33 UpdateCommittee {
34 gov_action_id: Option<GovActionId>,
35 cold_credentials: Vec<StakeCredential>,
36 hot_credentials: Vec<(StakeCredential, u64)>,
37 threshold: (u64, u64),
38 },
39 NewConstitution {
40 gov_action_id: Option<GovActionId>,
41 constitution: Constitution,
42 },
43 Information,
44}
45
46#[derive(Debug, PartialEq, Eq, Clone)]
47pub struct GovAction {
48 pub inner: PallasGovAction,
49}
50
51impl GovAction {
52 pub fn new(gov_action: GovActionKind) -> Result<Self, String> {
53 let pallas_gov_action = match gov_action {
54 GovActionKind::ParameterChange {
55 gov_action_id,
56 protocol_param_update,
57 script_hash,
58 } => PallasGovAction::ParameterChange(
59 gov_action_id.map(|id| id.inner),
60 Box::new(protocol_param_update.inner),
61 script_hash.map(|hash_str| {
62 Hash::<28>::from_str(&hash_str).expect("Invalid script hash length")
63 }),
64 ),
65 GovActionKind::HardForkInitiation {
66 gov_action_id,
67 protocol_version,
68 } => PallasGovAction::HardForkInitiation(
69 gov_action_id.map(|id| id.inner),
70 protocol_version,
71 ),
72 GovActionKind::TreasuryWithdrawals {
73 withdrawals,
74 script_hash,
75 } => {
76 let mut pallas_withdrawals = BTreeMap::new();
77 for (reward_account, amount) in withdrawals {
78 pallas_withdrawals.insert(reward_account.inner, amount);
79 }
80 PallasGovAction::TreasuryWithdrawals(
81 pallas_withdrawals,
82 script_hash.map(|hash_str| {
83 Hash::<28>::from_str(&hash_str).expect("Invalid script hash length")
84 }),
85 )
86 }
87 GovActionKind::NoConfidence { gov_action_id } => {
88 PallasGovAction::NoConfidence(gov_action_id.map(|id| id.inner))
89 }
90 GovActionKind::UpdateCommittee {
91 gov_action_id,
92 cold_credentials,
93 hot_credentials,
94 threshold,
95 } => {
96 let mut pallas_hot_credentials = BTreeMap::new();
97 for (cred, epoch) in hot_credentials {
98 pallas_hot_credentials.insert(cred.inner, epoch);
99 }
100 PallasGovAction::UpdateCommittee(
101 gov_action_id.map(|id| id.inner),
102 Set::from(
103 cold_credentials
104 .into_iter()
105 .map(|cred| cred.inner)
106 .collect::<Vec<PallasStakeCredential>>(),
107 ),
108 pallas_hot_credentials,
109 parse_rational_number(threshold),
110 )
111 }
112 GovActionKind::NewConstitution {
113 gov_action_id,
114 constitution,
115 } => PallasGovAction::NewConstitution(
116 gov_action_id.map(|id| id.inner),
117 constitution.inner,
118 ),
119 GovActionKind::Information => PallasGovAction::Information,
120 };
121
122 Ok(Self {
123 inner: pallas_gov_action,
124 })
125 }
126
127 pub fn encode(&self) -> String {
128 hex::encode(
129 self.inner
130 .encode_fragment()
131 .expect("encoding failed at GovAction"),
132 )
133 }
134
135 pub fn decode_bytes(bytes: &[u8]) -> Result<Self, String> {
136 let inner = PallasGovAction::decode_fragment(&bytes)
137 .map_err(|e| format!("Fragment decode error: {}", e.to_string()))?;
138 Ok(Self { inner })
139 }
140}