1use fedimint_core::Amount;
2use fedimint_core::core::{ModuleKind, OperationId};
3use fedimint_eventlog::{
4 Event, EventKind, EventPersistence, PersistedLogEntry, StructuredPaymentEvents,
5 filter_events_by_kind, 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 const KIND: EventKind = EventKind::from_static("outgoing-payment-started");
29 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 const KIND: EventKind = EventKind::from_static("outgoing-payment-succeeded");
48 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 const KIND: EventKind = EventKind::from_static("outgoing-payment-failed");
67 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 const KIND: EventKind = EventKind::from_static("incoming-payment-started");
92 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 const KIND: EventKind = EventKind::from_static("incoming-payment-succeeded");
108 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 const KIND: EventKind = EventKind::from_static("incoming-payment-failed");
124 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 const KIND: EventKind = EventKind::from_static("complete-lightning-payment-succeeded");
138 const PERSISTENCE: EventPersistence = EventPersistence::Persistent;
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 None,
171 |start_event, success_event, latency| {
172 if start_event.contract_id == success_event.contract_id {
173 success_event
174 .outgoing_contract
175 .amount
176 .checked_sub(start_event.invoice_amount)
177 .map(|fee| (latency.as_millis() as u64, fee))
178 } else {
179 None
180 }
181 },
182 )
183 .collect::<Vec<_>>();
184
185 let outgoing_failure_stats = join_events::<OutgoingPaymentStarted, OutgoingPaymentFailed, u64>(
186 &outgoing_start_events,
187 &outgoing_failure_events,
188 None,
189 |start_event, fail_event, latency| {
190 if start_event.contract_id == fail_event.contract_id {
191 Some(latency.as_millis() as u64)
192 } else {
193 None
194 }
195 },
196 )
197 .collect::<Vec<_>>();
198
199 let incoming_start_events = filter_events_by_kind(
200 all_events,
201 fedimint_ln_common::KIND,
202 IncomingPaymentStarted::KIND,
203 )
204 .collect::<Vec<_>>();
205 let incoming_success_events = filter_events_by_kind(
206 all_events,
207 fedimint_ln_common::KIND,
208 IncomingPaymentSucceeded::KIND,
209 )
210 .collect::<Vec<_>>();
211 let incoming_failure_events = filter_events_by_kind(
212 all_events,
213 fedimint_ln_common::KIND,
214 IncomingPaymentFailed::KIND,
215 )
216 .collect::<Vec<_>>();
217 let incoming_success_stats =
218 join_events::<IncomingPaymentStarted, IncomingPaymentSucceeded, (u64, Amount)>(
219 &incoming_start_events,
220 &incoming_success_events,
221 None,
222 |start_event, success_event, latency| {
223 if start_event.payment_hash == success_event.payment_hash {
224 start_event
225 .contract_amount
226 .checked_sub(start_event.invoice_amount)
227 .map(|fee| (latency.as_millis() as u64, fee))
228 } else {
229 None
230 }
231 },
232 )
233 .collect::<Vec<_>>();
234
235 let incoming_failure_stats = join_events::<IncomingPaymentStarted, IncomingPaymentFailed, u64>(
236 &incoming_start_events,
237 &incoming_failure_events,
238 None,
239 |start_event, fail_event, latency| {
240 if start_event.payment_hash == fail_event.payment_hash {
241 Some(latency.as_millis() as u64)
242 } else {
243 None
244 }
245 },
246 )
247 .collect::<Vec<_>>();
248
249 let outgoing = StructuredPaymentEvents::new(&outgoing_success_stats, outgoing_failure_stats);
250 let incoming = StructuredPaymentEvents::new(&incoming_success_stats, incoming_failure_stats);
251 (outgoing, incoming)
252}