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#[derive(Serialize, Deserialize, Debug)]
15pub struct OutgoingPaymentStarted {
16 pub contract_id: ContractId,
18
19 pub invoice_amount: Amount,
21
22 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#[derive(Serialize, Deserialize, Debug)]
34pub struct OutgoingPaymentSucceeded {
35 pub outgoing_contract: OutgoingContractAccount,
37
38 pub contract_id: ContractId,
40
41 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#[derive(Serialize, Deserialize, Debug)]
53pub struct OutgoingPaymentFailed {
54 pub outgoing_contract: OutgoingContractAccount,
56
57 pub contract_id: ContractId,
59
60 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#[derive(Serialize, Deserialize, Debug)]
72pub struct IncomingPaymentStarted {
73 pub contract_id: ContractId,
75
76 pub payment_hash: bitcoin::hashes::sha256::Hash,
78
79 pub invoice_amount: Amount,
81
82 pub contract_amount: Amount,
84
85 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#[derive(Serialize, Deserialize, Debug)]
97pub struct IncomingPaymentSucceeded {
98 pub payment_hash: bitcoin::hashes::sha256::Hash,
100
101 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#[derive(Serialize, Deserialize, Debug)]
113pub struct IncomingPaymentFailed {
114 pub payment_hash: bitcoin::hashes::sha256::Hash,
116
117 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#[derive(Serialize, Deserialize, Debug)]
130pub struct CompleteLightningPaymentSucceeded {
131 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
141pub 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}