penumbra_sdk_stake/
undelegate.rs1use penumbra_sdk_asset::{Balance, Value};
2use penumbra_sdk_num::Amount;
3use penumbra_sdk_proto::{penumbra::core::component::stake::v1 as pb, DomainType};
4use penumbra_sdk_sct::epoch::Epoch;
5use penumbra_sdk_txhash::{EffectHash, EffectingData};
6use serde::{Deserialize, Serialize};
7
8use crate::{DelegationToken, IdentityKey, UnbondingToken};
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(try_from = "pb::Undelegate", into = "pb::Undelegate")]
13pub struct Undelegate {
14 pub validator_identity: IdentityKey,
16 pub from_epoch: Epoch,
19 pub unbonded_amount: Amount,
21 pub delegation_amount: Amount,
27}
28
29impl EffectingData for Undelegate {
30 fn effect_hash(&self) -> EffectHash {
31 EffectHash::from_proto_effecting_data(&self.to_proto())
33 }
34}
35
36impl Undelegate {
37 pub fn balance(&self) -> Balance {
39 let undelegation: Balance = self.unbonded_value().into();
40 let delegation: Balance = self.delegation_value().into();
41
42 undelegation - delegation
44 }
45
46 pub fn unbonding_token(&self) -> UnbondingToken {
47 UnbondingToken::new(
51 self.validator_identity.clone(),
52 self.from_epoch.start_height,
53 )
54 }
55
56 pub fn unbonded_value(&self) -> Value {
58 Value {
59 amount: self.unbonded_amount,
60 asset_id: self.unbonding_token().id(),
61 }
62 }
63
64 pub fn delegation_token(&self) -> DelegationToken {
65 DelegationToken::new(self.validator_identity.clone())
66 }
67
68 pub fn delegation_value(&self) -> Value {
70 Value {
71 amount: self.delegation_amount,
72 asset_id: self.delegation_token().id(),
73 }
74 }
75}
76
77impl DomainType for Undelegate {
78 type Proto = pb::Undelegate;
79}
80
81impl From<Undelegate> for pb::Undelegate {
82 #[allow(deprecated)]
83 fn from(d: Undelegate) -> Self {
84 pb::Undelegate {
85 validator_identity: Some(d.validator_identity.into()),
86 unbonded_amount: Some(d.unbonded_amount.into()),
87 delegation_amount: Some(d.delegation_amount.into()),
88 from_epoch: Some(d.from_epoch.into()),
89 start_epoch_index: 0,
90 }
91 }
92}
93
94impl TryFrom<pb::Undelegate> for Undelegate {
95 type Error = anyhow::Error;
96 fn try_from(d: pb::Undelegate) -> Result<Self, Self::Error> {
97 Ok(Self {
98 validator_identity: d
99 .validator_identity
100 .ok_or_else(|| anyhow::anyhow!("missing validator_identity"))?
101 .try_into()?,
102 from_epoch: d
103 .from_epoch
104 .ok_or_else(|| anyhow::anyhow!("missing from_epoch"))?
105 .try_into()?,
106 unbonded_amount: d
107 .unbonded_amount
108 .ok_or_else(|| anyhow::anyhow!("missing unbonded_amount"))?
109 .try_into()?,
110 delegation_amount: d
111 .delegation_amount
112 .ok_or_else(|| anyhow::anyhow!("missing delegation_amount"))?
113 .try_into()?,
114 })
115 }
116}