penumbra_sdk_dex/
swap_execution.rs1use anyhow::Result;
2use penumbra_sdk_asset::Value;
3use penumbra_sdk_num::fixpoint::U128x128;
4use penumbra_sdk_proto::{penumbra::core::component::dex::v1 as pb, DomainType};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(try_from = "pb::SwapExecution", into = "pb::SwapExecution")]
10pub struct SwapExecution {
11 pub traces: Vec<Vec<Value>>,
12 pub input: Value,
14 pub output: Value,
16}
17
18impl SwapExecution {
19 pub fn max_price(&self) -> Option<U128x128> {
21 let Some((input, output)) = self.traces.last().and_then(|trace| {
22 let input = trace.first()?;
23 let output = trace.last()?;
24 Some((input, output))
25 }) else {
26 return None;
27 };
28
29 let price = U128x128::ratio(input.amount, output.amount).ok()?;
30 Some(price)
31 }
32}
33
34impl DomainType for SwapExecution {
35 type Proto = pb::SwapExecution;
36}
37
38impl TryFrom<pb::SwapExecution> for SwapExecution {
39 type Error = anyhow::Error;
40 fn try_from(se: pb::SwapExecution) -> Result<Self> {
41 Ok(Self {
42 traces: se
43 .traces
44 .into_iter()
45 .map(|vt| {
46 vt.value
47 .into_iter()
48 .map(TryInto::try_into)
49 .collect::<Result<Vec<_>>>()
50 })
51 .collect::<Result<Vec<_>>>()?,
52 input: se
53 .input
54 .ok_or_else(|| anyhow::anyhow!("missing input"))?
55 .try_into()?,
56 output: se
57 .output
58 .ok_or_else(|| anyhow::anyhow!("missing output"))?
59 .try_into()?,
60 })
61 }
62}
63
64impl From<SwapExecution> for pb::SwapExecution {
65 fn from(se: SwapExecution) -> Self {
66 pb::SwapExecution {
67 traces: se
68 .traces
69 .into_iter()
70 .map(|vt| pb::swap_execution::Trace {
71 value: vt.into_iter().map(Into::into).collect(),
72 })
73 .collect(),
74 input: Some(se.input.into()),
75 output: Some(se.output.into()),
76 }
77 }
78}