fedimint_mintv2_client/
receive.rs1use fedimint_client::DynGlobalClientContext;
2use fedimint_client_module::module::ClientContext;
3use fedimint_client_module::sm::{ClientSMDatabaseTransaction, State, StateTransition};
4use fedimint_core::TransactionId;
5use fedimint_core::core::OperationId;
6use fedimint_core::encoding::{Decodable, Encodable};
7
8use crate::event::{ReceivePaymentStatus, ReceivePaymentUpdateEvent};
9use crate::{MintClientContext, MintClientModule};
10
11#[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
12pub struct ReceiveStateMachine {
13 pub common: ReceiveSMCommon,
14 pub state: ReceiveSMState,
15}
16
17impl ReceiveStateMachine {
18 pub fn update(&self, state: ReceiveSMState) -> Self {
19 Self {
20 common: self.common.clone(),
21 state,
22 }
23 }
24}
25
26#[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
27pub struct ReceiveSMCommon {
28 pub operation_id: OperationId,
29 pub txid: TransactionId,
30}
31
32#[derive(Debug, Clone, Eq, PartialEq, Hash, Decodable, Encodable)]
33pub enum ReceiveSMState {
34 Pending,
35 Success,
36 Rejected(String),
37}
38
39impl State for ReceiveStateMachine {
40 type ModuleContext = MintClientContext;
41
42 fn transitions(
43 &self,
44 context: &Self::ModuleContext,
45 global_context: &DynGlobalClientContext,
46 ) -> Vec<StateTransition<Self>> {
47 let client_ctx = context.client_ctx.clone();
48
49 match &self.state {
50 ReceiveSMState::Pending => vec![StateTransition::new(
51 Self::await_tx_outcome(global_context.clone(), self.common.txid),
52 move |dbtx, result, old_state| {
53 Box::pin(Self::transition_tx_outcome(
54 client_ctx.clone(),
55 dbtx,
56 result,
57 old_state,
58 ))
59 },
60 )],
61 ReceiveSMState::Success | ReceiveSMState::Rejected(..) => vec![],
62 }
63 }
64
65 fn operation_id(&self) -> OperationId {
66 self.common.operation_id
67 }
68}
69
70impl ReceiveStateMachine {
71 async fn await_tx_outcome(
72 global_context: DynGlobalClientContext,
73 txid: TransactionId,
74 ) -> Result<(), String> {
75 global_context.await_tx_accepted(txid).await
76 }
77
78 async fn transition_tx_outcome(
79 client_ctx: ClientContext<MintClientModule>,
80 dbtx: &mut ClientSMDatabaseTransaction<'_, '_>,
81 result: Result<(), String>,
82 old_state: ReceiveStateMachine,
83 ) -> ReceiveStateMachine {
84 let (status, new_state) = match result {
85 Ok(()) => (ReceivePaymentStatus::Success, ReceiveSMState::Success),
86 Err(e) => (ReceivePaymentStatus::Rejected, ReceiveSMState::Rejected(e)),
87 };
88
89 client_ctx
90 .log_event(
91 &mut dbtx.module_tx(),
92 ReceivePaymentUpdateEvent {
93 operation_id: old_state.common.operation_id,
94 status,
95 },
96 )
97 .await;
98
99 old_state.update(new_state)
100 }
101}