penumbra_dex/lp/
action.rsuse serde::{Deserialize, Serialize};
use penumbra_asset::{balance, Balance, Value};
use penumbra_proto::{penumbra::core::component::dex::v1 as pb, DomainType};
use penumbra_txhash::{EffectHash, EffectingData};
use super::{position, position::Position, LpNft};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(try_from = "pb::PositionOpen", into = "pb::PositionOpen")]
pub struct PositionOpen {
pub position: Position,
}
impl EffectingData for PositionOpen {
fn effect_hash(&self) -> EffectHash {
EffectHash::from_proto_effecting_data(&self.to_proto())
}
}
impl PositionOpen {
pub fn balance(&self) -> Balance {
let opened_position_nft = Value {
amount: 1u64.into(),
asset_id: LpNft::new(self.position.id(), position::State::Opened).asset_id(),
};
let reserves = self.position.reserves.balance(&self.position.phi.pair);
Balance::from(opened_position_nft) - reserves
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(try_from = "pb::PositionClose", into = "pb::PositionClose")]
pub struct PositionClose {
pub position_id: position::Id,
}
impl EffectingData for PositionClose {
fn effect_hash(&self) -> EffectHash {
EffectHash::from_proto_effecting_data(&self.to_proto())
}
}
impl PositionClose {
pub fn balance(&self) -> Balance {
let opened_position_nft = Value {
amount: 1u64.into(),
asset_id: LpNft::new(self.position_id, position::State::Opened).asset_id(),
};
let closed_position_nft = Value {
amount: 1u64.into(),
asset_id: LpNft::new(self.position_id, position::State::Closed).asset_id(),
};
Balance::from(closed_position_nft) - opened_position_nft
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(try_from = "pb::PositionWithdraw", into = "pb::PositionWithdraw")]
pub struct PositionWithdraw {
pub position_id: position::Id,
pub reserves_commitment: balance::Commitment,
pub sequence: u64,
}
impl EffectingData for PositionWithdraw {
fn effect_hash(&self) -> EffectHash {
EffectHash::from_proto_effecting_data(&self.to_proto())
}
}
impl DomainType for PositionOpen {
type Proto = pb::PositionOpen;
}
impl From<PositionOpen> for pb::PositionOpen {
fn from(value: PositionOpen) -> Self {
Self {
position: Some(value.position.into()),
}
}
}
impl TryFrom<pb::PositionOpen> for PositionOpen {
type Error = anyhow::Error;
fn try_from(value: pb::PositionOpen) -> Result<Self, Self::Error> {
Ok(Self {
position: value
.position
.ok_or_else(|| anyhow::anyhow!("missing position"))?
.try_into()?,
})
}
}
impl DomainType for PositionClose {
type Proto = pb::PositionClose;
}
impl From<PositionClose> for pb::PositionClose {
fn from(value: PositionClose) -> Self {
Self {
position_id: Some(value.position_id.into()),
}
}
}
impl TryFrom<pb::PositionClose> for PositionClose {
type Error = anyhow::Error;
fn try_from(value: pb::PositionClose) -> Result<Self, Self::Error> {
Ok(Self {
position_id: value
.position_id
.ok_or_else(|| anyhow::anyhow!("missing position_id"))?
.try_into()?,
})
}
}
impl DomainType for PositionWithdraw {
type Proto = pb::PositionWithdraw;
}
impl From<PositionWithdraw> for pb::PositionWithdraw {
fn from(value: PositionWithdraw) -> Self {
Self {
position_id: Some(value.position_id.into()),
reserves_commitment: Some(value.reserves_commitment.into()),
sequence: value.sequence,
}
}
}
impl TryFrom<pb::PositionWithdraw> for PositionWithdraw {
type Error = anyhow::Error;
fn try_from(value: pb::PositionWithdraw) -> Result<Self, Self::Error> {
Ok(Self {
position_id: value
.position_id
.ok_or_else(|| anyhow::anyhow!("missing position_id"))?
.try_into()?,
reserves_commitment: value
.reserves_commitment
.ok_or_else(|| anyhow::anyhow!("missing balance_commitment"))?
.try_into()?,
sequence: value.sequence,
})
}
}