penumbra_dex/component/action_handler/position/
close.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
use anyhow::Result;
use async_trait::async_trait;
use cnidarium::StateWrite;
use cnidarium_component::ActionHandler;
use penumbra_proto::{DomainType as _, StateWriteProto as _};

use crate::{component::PositionManager, event, lp::action::PositionClose};

#[async_trait]
/// Debits an opened position NFT and credits a closed position NFT.
impl ActionHandler for PositionClose {
    type CheckStatelessContext = ();
    async fn check_stateless(&self, _context: ()) -> Result<()> {
        // Nothing to do: the only validation is of the state change,
        // and that's done by the value balance mechanism.
        Ok(())
    }

    async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
        // We don't want to actually close the position here, because otherwise
        // the economic effects could depend on intra-block ordering, and we'd
        // lose the ability to do block-scoped JIT liquidity, where a single
        // transaction opens and closes a position, keeping liquidity live only
        // during that block's batch swap execution.
        state.queue_close_position(self.position_id);

        // queue position close you will...
        state.record_proto(
            event::EventQueuePositionClose {
                position_id: self.position_id,
            }
            .to_proto(),
        );

        Ok(())
    }
}