penumbra_sdk_dex/swap/
action.rs1use anyhow::Context;
2use ark_ff::Zero;
3use decaf377::Fr;
4use penumbra_sdk_asset::{balance, Balance, Value};
5use penumbra_sdk_num::Amount;
6use penumbra_sdk_proto::{
7 core::component::dex::v1 as pbc, penumbra::core::component::dex::v1 as pb, DomainType,
8};
9use penumbra_sdk_txhash::{EffectHash, EffectingData};
10use serde::{Deserialize, Serialize};
11
12use crate::TradingPair;
13
14use super::{proof::SwapProof, SwapPayload};
15
16#[derive(Clone, Debug)]
17pub struct Swap {
18 pub proof: SwapProof,
19 pub body: Body,
20}
21
22impl Swap {
23 pub fn balance_commitment_inner(&self) -> balance::Commitment {
25 let input_1 = Value {
26 amount: self.body.delta_1_i,
27 asset_id: self.body.trading_pair.asset_1(),
28 };
29 let input_1 = -Balance::from(input_1);
30 let commitment_input_1 = input_1.commit(Fr::zero());
31 let input_2 = Value {
32 amount: self.body.delta_2_i,
33 asset_id: self.body.trading_pair.asset_2(),
34 };
35 let input_2 = -Balance::from(input_2);
36 let commitment_input_2 = input_2.commit(Fr::zero());
37
38 commitment_input_1 + commitment_input_2 + self.body.fee_commitment
39 }
40}
41
42impl EffectingData for Swap {
43 fn effect_hash(&self) -> EffectHash {
44 self.body.effect_hash()
47 }
48}
49
50impl DomainType for Swap {
51 type Proto = pb::Swap;
52}
53
54impl From<Swap> for pb::Swap {
55 fn from(s: Swap) -> Self {
56 let proof: pbc::ZkSwapProof = s.proof.into();
57 pb::Swap {
58 proof: Some(proof),
59 body: Some(s.body.into()),
60 }
61 }
62}
63
64impl TryFrom<pb::Swap> for Swap {
65 type Error = anyhow::Error;
66 fn try_from(s: pb::Swap) -> Result<Self, Self::Error> {
67 Ok(Self {
68 proof: s
69 .proof
70 .ok_or_else(|| anyhow::anyhow!("missing swap proof"))?
71 .try_into()
72 .context("swap proof malformed")?,
73 body: s
74 .body
75 .ok_or_else(|| anyhow::anyhow!("missing swap body"))?
76 .try_into()
77 .context("swap body malformed")?,
78 })
79 }
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83#[serde(try_from = "pb::SwapBody", into = "pb::SwapBody")]
84pub struct Body {
85 pub trading_pair: TradingPair,
86 pub delta_1_i: Amount,
87 pub delta_2_i: Amount,
88 pub fee_commitment: balance::Commitment,
89 pub payload: SwapPayload,
90}
91
92impl EffectingData for Body {
93 fn effect_hash(&self) -> EffectHash {
94 EffectHash::from_proto_effecting_data(&self.to_proto())
95 }
96}
97
98impl DomainType for Body {
99 type Proto = pb::SwapBody;
100}
101
102impl From<Body> for pb::SwapBody {
103 fn from(s: Body) -> Self {
104 pb::SwapBody {
105 trading_pair: Some(s.trading_pair.into()),
106 delta_1_i: Some(s.delta_1_i.into()),
107 delta_2_i: Some(s.delta_2_i.into()),
108 fee_commitment: Some(s.fee_commitment.into()),
109 payload: Some(s.payload.into()),
110 }
111 }
112}
113
114impl TryFrom<pb::SwapBody> for Body {
115 type Error = anyhow::Error;
116 fn try_from(s: pb::SwapBody) -> Result<Self, Self::Error> {
117 Ok(Self {
118 trading_pair: s
119 .trading_pair
120 .ok_or_else(|| anyhow::anyhow!("missing trading_pair"))?
121 .try_into()?,
122
123 delta_1_i: s
124 .delta_1_i
125 .ok_or_else(|| anyhow::anyhow!("missing delta_1"))?
126 .try_into()?,
127 delta_2_i: s
128 .delta_2_i
129 .ok_or_else(|| anyhow::anyhow!("missing delta_2"))?
130 .try_into()?,
131
132 fee_commitment: s
133 .fee_commitment
134 .ok_or_else(|| anyhow::anyhow!("missing fee_commitment"))?
135 .try_into()?,
136 payload: s
137 .payload
138 .ok_or_else(|| anyhow::anyhow!("missing payload"))?
139 .try_into()?,
140 })
141 }
142}