penumbra_sdk_dex/swap/
payload.rs1use anyhow::anyhow;
2use penumbra_sdk_keys::FullViewingKey;
3use penumbra_sdk_proto::penumbra::core::component::dex::v1 as pb;
4use serde::{Deserialize, Serialize};
5
6use super::{SwapCiphertext, SwapPlaintext};
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
9#[serde(try_from = "pb::SwapPayload", into = "pb::SwapPayload")]
10pub struct SwapPayload {
11 pub commitment: penumbra_sdk_tct::StateCommitment,
12 pub encrypted_swap: SwapCiphertext,
13}
14
15impl SwapPayload {
16 pub fn trial_decrypt(&self, fvk: &FullViewingKey) -> Option<SwapPlaintext> {
17 let swap = self
19 .encrypted_swap
20 .decrypt(fvk.outgoing(), self.commitment)
21 .ok()?;
22 tracing::debug!(swap_commitment = ?self.commitment, ?swap, "found swap while scanning");
23
24 if swap.swap_commitment() != self.commitment {
33 tracing::warn!("decrypted swap does not match provided swap commitment");
36 return None;
37 }
38
39 if !fvk.incoming().views_address(&swap.claim_address) {
41 tracing::warn!("decrypted swap that is not claimable by provided full viewing key");
44 return None;
45 }
46
47 Some(swap)
48 }
49}
50
51impl From<SwapPayload> for pb::SwapPayload {
52 fn from(msg: SwapPayload) -> Self {
53 pb::SwapPayload {
54 commitment: Some(msg.commitment.into()),
55 encrypted_swap: msg.encrypted_swap.0.to_vec(),
56 }
57 }
58}
59
60impl TryFrom<pb::SwapPayload> for SwapPayload {
61 type Error = anyhow::Error;
62
63 fn try_from(msg: pb::SwapPayload) -> Result<Self, Self::Error> {
64 let commitment = msg
65 .commitment
66 .ok_or_else(|| anyhow!("missing commitment"))?
67 .try_into()?;
68 let encrypted_swap = SwapCiphertext(
69 msg.encrypted_swap
70 .try_into()
71 .map_err(|_| anyhow!("expected correct length swap ciphertext"))?,
72 );
73 Ok(Self {
74 commitment,
75 encrypted_swap,
76 })
77 }
78}