penumbra_stake/
undelegate.rsuse penumbra_asset::{Balance, Value};
use penumbra_num::Amount;
use penumbra_proto::{penumbra::core::component::stake::v1 as pb, DomainType};
use penumbra_sct::epoch::Epoch;
use penumbra_txhash::{EffectHash, EffectingData};
use serde::{Deserialize, Serialize};
use crate::{DelegationToken, IdentityKey, UnbondingToken};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "pb::Undelegate", into = "pb::Undelegate")]
pub struct Undelegate {
pub validator_identity: IdentityKey,
pub from_epoch: Epoch,
pub unbonded_amount: Amount,
pub delegation_amount: Amount,
}
impl EffectingData for Undelegate {
fn effect_hash(&self) -> EffectHash {
EffectHash::from_proto_effecting_data(&self.to_proto())
}
}
impl Undelegate {
pub fn balance(&self) -> Balance {
let undelegation: Balance = self.unbonded_value().into();
let delegation: Balance = self.delegation_value().into();
undelegation - delegation
}
pub fn unbonding_token(&self) -> UnbondingToken {
UnbondingToken::new(
self.validator_identity.clone(),
self.from_epoch.start_height,
)
}
pub fn unbonded_value(&self) -> Value {
Value {
amount: self.unbonded_amount,
asset_id: self.unbonding_token().id(),
}
}
pub fn delegation_token(&self) -> DelegationToken {
DelegationToken::new(self.validator_identity.clone())
}
pub fn delegation_value(&self) -> Value {
Value {
amount: self.delegation_amount,
asset_id: self.delegation_token().id(),
}
}
}
impl DomainType for Undelegate {
type Proto = pb::Undelegate;
}
impl From<Undelegate> for pb::Undelegate {
#[allow(deprecated)]
fn from(d: Undelegate) -> Self {
pb::Undelegate {
validator_identity: Some(d.validator_identity.into()),
unbonded_amount: Some(d.unbonded_amount.into()),
delegation_amount: Some(d.delegation_amount.into()),
from_epoch: Some(d.from_epoch.into()),
start_epoch_index: 0,
}
}
}
impl TryFrom<pb::Undelegate> for Undelegate {
type Error = anyhow::Error;
fn try_from(d: pb::Undelegate) -> Result<Self, Self::Error> {
Ok(Self {
validator_identity: d
.validator_identity
.ok_or_else(|| anyhow::anyhow!("missing validator_identity"))?
.try_into()?,
from_epoch: d
.from_epoch
.ok_or_else(|| anyhow::anyhow!("missing from_epoch"))?
.try_into()?,
unbonded_amount: d
.unbonded_amount
.ok_or_else(|| anyhow::anyhow!("missing unbonded_amount"))?
.try_into()?,
delegation_amount: d
.delegation_amount
.ok_or_else(|| anyhow::anyhow!("missing delegation_amount"))?
.try_into()?,
})
}
}