penumbra_sdk_dex/component/action_handler/
swap.rs1use std::sync::Arc;
2
3use anyhow::{ensure, Result};
4use async_trait::async_trait;
5use cnidarium::StateWrite;
6use cnidarium_component::ActionHandler;
7use penumbra_sdk_proof_params::SWAP_PROOF_VERIFICATION_KEY;
8use penumbra_sdk_proto::{DomainType as _, StateWriteProto};
9use penumbra_sdk_sct::component::source::SourceContext;
10
11use crate::{
12 component::{InternalDexWrite, StateReadExt, SwapDataWrite, SwapManager},
13 event,
14 swap::{proof::SwapProofPublic, Swap},
15};
16
17#[async_trait]
18impl ActionHandler for Swap {
19 type CheckStatelessContext = ();
20 async fn check_stateless(&self, _context: ()) -> Result<()> {
21 if self.body.trading_pair.asset_1() == self.body.trading_pair.asset_2() {
23 anyhow::bail!("Trading pair must be distinct");
24 }
25
26 self.proof.verify(
27 &SWAP_PROOF_VERIFICATION_KEY,
28 SwapProofPublic {
29 balance_commitment: self.balance_commitment_inner(),
30 swap_commitment: self.body.payload.commitment,
31 fee_commitment: self.body.fee_commitment,
32 },
33 )?;
34
35 Ok(())
36 }
37
38 async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
39 let dex_params = state.get_dex_params().await?;
41
42 ensure!(
43 dex_params.is_enabled,
44 "Dex MUST be enabled to process swap actions."
45 );
46
47 let swap = self;
48
49 let flow = (swap.body.delta_1_i, swap.body.delta_2_i);
51 state
52 .accumulate_swap_flow(&swap.body.trading_pair, flow.into())
53 .await?;
54
55 let source = state.get_current_source().expect("source is set");
57 state
58 .add_swap_payload(self.body.payload.clone(), source)
59 .await;
60
61 let fixed_candidates = Arc::new(dex_params.fixed_candidates.clone());
63 state.add_recently_accessed_asset(
64 swap.body.trading_pair.asset_1(),
65 fixed_candidates.clone(),
66 );
67 state.add_recently_accessed_asset(swap.body.trading_pair.asset_2(), fixed_candidates);
68
69 state.record_proto(event::EventSwap::from(self).to_proto());
70
71 Ok(())
72 }
73}