penumbra_sdk_auction/component/action_handler/dutch/
end.rs

1use anyhow::{ensure, Result};
2use async_trait::async_trait;
3use cnidarium::StateWrite;
4use cnidarium_component::ActionHandler;
5use penumbra_sdk_proto::StateWriteProto;
6use tracing::instrument;
7
8use crate::auction::dutch::ActionDutchAuctionEnd;
9use crate::component::AuctionStoreRead;
10use crate::component::DutchAuctionManager;
11use crate::event;
12
13use anyhow::{bail, Context};
14
15#[async_trait]
16impl ActionHandler for ActionDutchAuctionEnd {
17    type CheckStatelessContext = ();
18    async fn check_stateless(&self, _context: ()) -> Result<()> {
19        Ok(())
20    }
21
22    #[instrument(name = "dutch_auction_end", skip(self, state))]
23    async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
24        let auction_id = self.auction_id;
25
26        let auction_state = state
27            .get_dutch_auction_by_id(auction_id)
28            .await
29            .context("the auction associated with this id is not a dutch auction")?;
30
31        let Some(auction) = auction_state else {
32            bail!("no auction found for id {auction_id}")
33        };
34
35        // Check that the sequence number for the auction state is 0 (opened) or 1 (closed).
36        ensure!(
37            matches!(auction.state.sequence, 0 | 1),
38            "auction MUST have a sequence number set to opened (0) or closed (1) (got: {})",
39            auction.state.sequence
40        );
41
42        // Keep a copy of the auction state for the event.
43        let auction_state = auction.state.clone();
44
45        // Terminate the auction
46        state.end_auction(auction).await?;
47        // Emit an event, tracing the reason for the auction ending.
48        state.record_proto(event::dutch_auction_closed_by_user(
49            auction_id,
50            auction_state,
51        ));
52
53        Ok(())
54    }
55}