penumbra_governance/proposal_submit/
action.rsuse serde::{Deserialize, Serialize};
use penumbra_asset::{Balance, Value, STAKING_TOKEN_ASSET_ID};
use penumbra_num::Amount;
use penumbra_proto::{penumbra::core::component::governance::v1 as pb, DomainType};
use penumbra_txhash::{EffectHash, EffectingData};
use crate::proposal::Proposal;
use crate::ProposalNft;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(try_from = "pb::ProposalSubmit", into = "pb::ProposalSubmit")]
pub struct ProposalSubmit {
pub proposal: Proposal,
pub deposit_amount: Amount,
}
impl EffectingData for ProposalSubmit {
fn effect_hash(&self) -> EffectHash {
EffectHash::from_proto_effecting_data(&self.to_proto())
}
}
impl ProposalSubmit {
pub fn balance(&self) -> Balance {
let deposit = self.deposit_value();
let proposal_nft = self.proposal_nft_value();
Balance::from(proposal_nft) - Balance::from(deposit)
}
fn deposit_value(&self) -> Value {
Value {
amount: self.deposit_amount,
asset_id: *STAKING_TOKEN_ASSET_ID,
}
}
pub fn proposal_nft_value(&self) -> Value {
Value {
amount: Amount::from(1u64),
asset_id: ProposalNft::deposit(self.proposal.id).denom().into(),
}
}
}
impl From<ProposalSubmit> for pb::ProposalSubmit {
fn from(value: ProposalSubmit) -> pb::ProposalSubmit {
pb::ProposalSubmit {
proposal: Some(value.proposal.into()),
deposit_amount: Some(value.deposit_amount.into()),
}
}
}
impl TryFrom<pb::ProposalSubmit> for ProposalSubmit {
type Error = anyhow::Error;
fn try_from(msg: pb::ProposalSubmit) -> Result<Self, Self::Error> {
Ok(ProposalSubmit {
proposal: msg
.proposal
.ok_or_else(|| anyhow::anyhow!("missing proposal in `Propose`"))?
.try_into()?,
deposit_amount: msg
.deposit_amount
.ok_or_else(|| anyhow::anyhow!("missing deposit amount in `Propose`"))?
.try_into()?,
})
}
}
impl DomainType for ProposalSubmit {
type Proto = pb::ProposalSubmit;
}