penumbra_sdk_governance/proposal_withdraw/
action.rs

1use serde::{Deserialize, Serialize};
2
3use penumbra_sdk_asset::{Balance, Value};
4use penumbra_sdk_num::Amount;
5use penumbra_sdk_proto::{penumbra::core::component::governance::v1 as pb, DomainType};
6use penumbra_sdk_txhash::{EffectHash, EffectingData};
7
8use crate::ProposalNft;
9
10/// A withdrawal of a proposal.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(try_from = "pb::ProposalWithdraw", into = "pb::ProposalWithdraw")]
13pub struct ProposalWithdraw {
14    /// The proposal ID to withdraw.
15    pub proposal: u64,
16    // The reason the proposal was withdrawn.
17    pub reason: String,
18}
19
20impl EffectingData for ProposalWithdraw {
21    fn effect_hash(&self) -> EffectHash {
22        EffectHash::from_proto_effecting_data(&self.to_proto())
23    }
24}
25
26impl From<ProposalWithdraw> for pb::ProposalWithdraw {
27    fn from(value: ProposalWithdraw) -> pb::ProposalWithdraw {
28        pb::ProposalWithdraw {
29            proposal: value.proposal,
30            reason: value.reason,
31        }
32    }
33}
34
35impl ProposalWithdraw {
36    /// Compute a commitment to the value contributed to a transaction by this proposal withdrawal.
37    pub fn balance(&self) -> Balance {
38        let voting_proposal_nft = self.voting_proposal_nft_value();
39        let withdrawn_proposal_nft = self.withdrawn_proposal_nft();
40
41        // Proposal withdrawals consume the submitted proposal and produce a withdrawn proposal:
42        Balance::from(withdrawn_proposal_nft) - Balance::from(voting_proposal_nft)
43    }
44
45    /// Returns the [`Value`] of the proposal NFT.
46    fn voting_proposal_nft_value(&self) -> Value {
47        Value {
48            amount: Amount::from(1u64),
49            asset_id: ProposalNft::deposit(self.proposal).denom().into(),
50        }
51    }
52
53    /// Returns a withdrawal NFT.
54    fn withdrawn_proposal_nft(&self) -> Value {
55        Value {
56            amount: Amount::from(1u64),
57            asset_id: ProposalNft::unbonding_deposit(self.proposal).denom().into(),
58        }
59    }
60}
61
62impl TryFrom<pb::ProposalWithdraw> for ProposalWithdraw {
63    type Error = anyhow::Error;
64
65    fn try_from(msg: pb::ProposalWithdraw) -> Result<Self, Self::Error> {
66        Ok(ProposalWithdraw {
67            proposal: msg.proposal,
68            reason: msg.reason,
69        })
70    }
71}
72
73impl DomainType for ProposalWithdraw {
74    type Proto = pb::ProposalWithdraw;
75}