penumbra_sdk_auction/component/action_handler/dutch/
withdraw.rs

1use crate::auction::dutch::ActionDutchAuctionWithdraw;
2use crate::component::AuctionStoreRead;
3use crate::component::DutchAuctionManager;
4use anyhow::{bail, ensure, Context, Result};
5use ark_ff::Zero;
6use async_trait::async_trait;
7use cnidarium::StateWrite;
8use cnidarium_component::ActionHandler;
9use decaf377::Fr;
10
11#[async_trait]
12impl ActionHandler for ActionDutchAuctionWithdraw {
13    type CheckStatelessContext = ();
14    async fn check_stateless(&self, _context: ()) -> Result<()> {
15        ensure!(
16            self.seq >= 1,
17            "the sequence number MUST be greater or equal to 1 (got: {})",
18            self.seq
19        );
20
21        ensure!(
22            self.seq < u64::MAX,
23            "the sequence number maximum is `u64::MAX`"
24        );
25
26        Ok(())
27    }
28
29    async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
30        let auction_id = self.auction_id;
31
32        // Check that the auction exists and is a Dutch auction.
33        let auction_state = state
34            .get_dutch_auction_by_id(auction_id)
35            .await
36            .context("the auction associated with this id is not a dutch auction")?;
37
38        let Some(auction_state) = auction_state else {
39            bail!("no auction found for id {auction_id}")
40        };
41
42        // Check that sequence number is incremented by one.
43        ensure!(
44            self.seq == auction_state.state.sequence.saturating_add(1),
45            "the action sequence number MUST be incremented by one (previous: {}, action: {})",
46            self.seq,
47            auction_state.state.sequence
48        );
49
50        // Execute the withdrawal, zero-ing out the auction state
51        // and increasing its sequence number.
52        let withdrawn_balance = state.withdraw_auction(auction_state).await?;
53
54        // Check that the reported balance commitment, match the recorded reserves.
55        let expected_reserve_commitment = withdrawn_balance.commit(Fr::zero());
56
57        ensure!(
58            self.reserves_commitment == expected_reserve_commitment,
59            "the reported reserve commitment is incorrect"
60        );
61
62        Ok(())
63    }
64}