fedimint_gw_client/
events.rs

1use fedimint_core::Amount;
2use fedimint_core::core::{ModuleKind, OperationId};
3use fedimint_eventlog::{
4    Event, EventKind, PersistedLogEntry, StructuredPaymentEvents, filter_events_by_kind,
5    join_events,
6};
7use fedimint_ln_common::contracts::ContractId;
8use fedimint_ln_common::contracts::outgoing::OutgoingContractAccount;
9use serde::{Deserialize, Serialize};
10
11use super::pay::OutgoingPaymentError;
12
13/// LNv1 event that is emitted when an outgoing payment attempt is initiated.
14#[derive(Serialize, Deserialize, Debug)]
15pub struct OutgoingPaymentStarted {
16    /// The contract ID that uniquely identifies the outgoing contract.
17    pub contract_id: ContractId,
18
19    /// The amount of the invoice that is being paid.
20    pub invoice_amount: Amount,
21
22    /// The operation ID of the outgoing payment
23    pub operation_id: OperationId,
24}
25
26impl Event for OutgoingPaymentStarted {
27    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
28
29    const KIND: EventKind = EventKind::from_static("outgoing-payment-started");
30}
31
32/// LNv1 event that is emitted when an outgoing payment attempt has succeeded.
33#[derive(Serialize, Deserialize, Debug)]
34pub struct OutgoingPaymentSucceeded {
35    /// LNv1 outgoing contract
36    pub outgoing_contract: OutgoingContractAccount,
37
38    /// The contract ID that uniquely identifies the outgoing contract.
39    pub contract_id: ContractId,
40
41    /// The preimage acquired from successfully paying the invoice.
42    pub preimage: String,
43}
44
45impl Event for OutgoingPaymentSucceeded {
46    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
47
48    const KIND: EventKind = EventKind::from_static("outgoing-payment-succeeded");
49}
50
51/// LNv1 event that is emitted when an outgoing payment attempt has failed.
52#[derive(Serialize, Deserialize, Debug)]
53pub struct OutgoingPaymentFailed {
54    /// LNv1 outgoing contract
55    pub outgoing_contract: OutgoingContractAccount,
56
57    /// The contract ID that uniquely identifies the outgoing contract.
58    pub contract_id: ContractId,
59
60    /// The reason the outgoing payment failed.
61    pub error: OutgoingPaymentError,
62}
63
64impl Event for OutgoingPaymentFailed {
65    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
66
67    const KIND: EventKind = EventKind::from_static("outgoing-payment-failed");
68}
69
70/// LNv1 event that is emitted when an incoming payment attempt has started.
71#[derive(Serialize, Deserialize, Debug)]
72pub struct IncomingPaymentStarted {
73    /// The contract ID that uniquely identifies the incoming contract.
74    pub contract_id: ContractId,
75
76    /// The payment hash of the invoice that is being paid.
77    pub payment_hash: bitcoin::hashes::sha256::Hash,
78
79    /// The amount specified in the invoice.
80    pub invoice_amount: Amount,
81
82    /// The amount offered in the contract.
83    pub contract_amount: Amount,
84
85    /// The operation ID of the outgoing payment
86    pub operation_id: OperationId,
87}
88
89impl Event for IncomingPaymentStarted {
90    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
91
92    const KIND: EventKind = EventKind::from_static("incoming-payment-started");
93}
94
95/// LNv1 event that is emitted when an incoming payment attempt was successful.
96#[derive(Serialize, Deserialize, Debug)]
97pub struct IncomingPaymentSucceeded {
98    /// The payment hash of the invoice that was paid.
99    pub payment_hash: bitcoin::hashes::sha256::Hash,
100
101    /// The decrypted preimage that was acquired from the federation.
102    pub preimage: String,
103}
104
105impl Event for IncomingPaymentSucceeded {
106    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
107
108    const KIND: EventKind = EventKind::from_static("incoming-payment-succeeded");
109}
110
111/// LNv1 event that is emitted when an incoming payment attempt has failed.
112#[derive(Serialize, Deserialize, Debug)]
113pub struct IncomingPaymentFailed {
114    /// The payment hash of the invoice that failed to be paid.
115    pub payment_hash: bitcoin::hashes::sha256::Hash,
116
117    /// The reason the incoming payment attempt failed.
118    pub error: String,
119}
120
121impl Event for IncomingPaymentFailed {
122    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
123
124    const KIND: EventKind = EventKind::from_static("incoming-payment-failed");
125}
126
127/// LNv1 event that is emitted when a preimage was successfully revealed to the
128/// Lightning Network.
129#[derive(Serialize, Deserialize, Debug)]
130pub struct CompleteLightningPaymentSucceeded {
131    /// The payment hash of the payment.
132    pub payment_hash: bitcoin::hashes::sha256::Hash,
133}
134
135impl Event for CompleteLightningPaymentSucceeded {
136    const MODULE: Option<ModuleKind> = Some(fedimint_ln_common::KIND);
137
138    const KIND: EventKind = EventKind::from_static("complete-lightning-payment-succeeded");
139}
140
141/// Computes the `StructurePaymentEvents` for all LNv1 payments.
142///
143/// Filters the event set for LNv1 events and joins them together.
144pub fn compute_lnv1_stats(
145    all_events: &[PersistedLogEntry],
146) -> (StructuredPaymentEvents, StructuredPaymentEvents) {
147    let outgoing_start_events = filter_events_by_kind(
148        all_events,
149        fedimint_ln_common::KIND,
150        OutgoingPaymentStarted::KIND,
151    )
152    .collect::<Vec<_>>();
153    let outgoing_success_events = filter_events_by_kind(
154        all_events,
155        fedimint_ln_common::KIND,
156        OutgoingPaymentSucceeded::KIND,
157    )
158    .collect::<Vec<_>>();
159    let outgoing_failure_events = filter_events_by_kind(
160        all_events,
161        fedimint_ln_common::KIND,
162        OutgoingPaymentFailed::KIND,
163    )
164    .collect::<Vec<_>>();
165
166    let outgoing_success_stats =
167        join_events::<OutgoingPaymentStarted, OutgoingPaymentSucceeded, (u64, Amount)>(
168            &outgoing_start_events,
169            &outgoing_success_events,
170            |start_event, success_event, latency| {
171                if start_event.contract_id == success_event.contract_id {
172                    success_event
173                        .outgoing_contract
174                        .amount
175                        .checked_sub(start_event.invoice_amount)
176                        .map(|fee| (latency, fee))
177                } else {
178                    None
179                }
180            },
181        )
182        .collect::<Vec<_>>();
183
184    let outgoing_failure_stats = join_events::<OutgoingPaymentStarted, OutgoingPaymentFailed, u64>(
185        &outgoing_start_events,
186        &outgoing_failure_events,
187        |start_event, fail_event, latency| {
188            if start_event.contract_id == fail_event.contract_id {
189                Some(latency)
190            } else {
191                None
192            }
193        },
194    )
195    .collect::<Vec<_>>();
196
197    let incoming_start_events = filter_events_by_kind(
198        all_events,
199        fedimint_ln_common::KIND,
200        IncomingPaymentStarted::KIND,
201    )
202    .collect::<Vec<_>>();
203    let incoming_success_events = filter_events_by_kind(
204        all_events,
205        fedimint_ln_common::KIND,
206        IncomingPaymentSucceeded::KIND,
207    )
208    .collect::<Vec<_>>();
209    let incoming_failure_events = filter_events_by_kind(
210        all_events,
211        fedimint_ln_common::KIND,
212        IncomingPaymentFailed::KIND,
213    )
214    .collect::<Vec<_>>();
215    let incoming_success_stats =
216        join_events::<IncomingPaymentStarted, IncomingPaymentSucceeded, (u64, Amount)>(
217            &incoming_start_events,
218            &incoming_success_events,
219            |start_event, success_event, latency| {
220                if start_event.payment_hash == success_event.payment_hash {
221                    start_event
222                        .contract_amount
223                        .checked_sub(start_event.invoice_amount)
224                        .map(|fee| (latency, fee))
225                } else {
226                    None
227                }
228            },
229        )
230        .collect::<Vec<_>>();
231
232    let incoming_failure_stats = join_events::<IncomingPaymentStarted, IncomingPaymentFailed, u64>(
233        &incoming_start_events,
234        &incoming_failure_events,
235        |start_event, fail_event, latency| {
236            if start_event.payment_hash == fail_event.payment_hash {
237                Some(latency)
238            } else {
239                None
240            }
241        },
242    )
243    .collect::<Vec<_>>();
244
245    let outgoing = StructuredPaymentEvents::new(&outgoing_success_stats, outgoing_failure_stats);
246    let incoming = StructuredPaymentEvents::new(&incoming_success_stats, incoming_failure_stats);
247    (outgoing, incoming)
248}