whisky_pallas/wrapper/transaction_body/
gov_action.rs

1use 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}