1use std::time::SystemTime;
2
3use fedimint_core::Amount;
4use fedimint_core::config::FederationId;
5use fedimint_core::core::ModuleKind;
6use fedimint_eventlog::{
7 Event, EventKind, PersistedLogEntry, StructuredPaymentEvents, filter_events_by_kind,
8 join_events,
9};
10use fedimint_lnv2_common::contracts::{Commitment, OutgoingContract, PaymentImage};
11use serde::{Deserialize, Serialize};
12use serde_millis;
13
14use super::send_sm::Cancelled;
15
16#[derive(Serialize, Deserialize, Debug)]
18pub struct OutgoingPaymentStarted {
19 #[serde(with = "serde_millis")]
22 pub operation_start: SystemTime,
23
24 pub outgoing_contract: OutgoingContract,
26
27 pub min_contract_amount: Amount,
30
31 pub invoice_amount: Amount,
33
34 pub max_delay: u64,
36}
37
38impl Event for OutgoingPaymentStarted {
39 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
40
41 const KIND: EventKind = EventKind::from_static("outgoing-payment-started");
42}
43
44#[derive(Serialize, Deserialize, Debug)]
46pub struct OutgoingPaymentSucceeded {
47 pub payment_image: PaymentImage,
49
50 pub target_federation: Option<FederationId>,
52}
53
54impl Event for OutgoingPaymentSucceeded {
55 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
56
57 const KIND: EventKind = EventKind::from_static("outgoing-payment-succeeded");
58}
59
60#[derive(Serialize, Deserialize, Debug)]
62pub struct OutgoingPaymentFailed {
63 pub payment_image: PaymentImage,
65
66 pub error: Cancelled,
68}
69
70impl Event for OutgoingPaymentFailed {
71 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
72
73 const KIND: EventKind = EventKind::from_static("outgoing-payment-failed");
74}
75
76#[derive(Serialize, Deserialize, Debug)]
79pub struct IncomingPaymentStarted {
80 #[serde(with = "serde_millis")]
83 pub operation_start: SystemTime,
84
85 pub incoming_contract_commitment: Commitment,
87
88 pub invoice_amount: Amount,
90}
91
92impl Event for IncomingPaymentStarted {
93 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
94
95 const KIND: EventKind = EventKind::from_static("incoming-payment-started");
96}
97
98#[derive(Serialize, Deserialize, Debug)]
101pub struct IncomingPaymentSucceeded {
102 pub payment_image: PaymentImage,
104}
105
106impl Event for IncomingPaymentSucceeded {
107 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
108
109 const KIND: EventKind = EventKind::from_static("incoming-payment-succeeded");
110}
111
112#[derive(Serialize, Deserialize, Debug)]
114pub struct IncomingPaymentFailed {
115 pub payment_image: PaymentImage,
117
118 pub error: String,
120}
121
122impl Event for IncomingPaymentFailed {
123 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
124
125 const KIND: EventKind = EventKind::from_static("incoming-payment-failed");
126}
127
128#[derive(Serialize, Deserialize, Debug)]
132pub struct CompleteLightningPaymentSucceeded {
133 pub payment_image: PaymentImage,
135}
136
137impl Event for CompleteLightningPaymentSucceeded {
138 const MODULE: Option<ModuleKind> = Some(fedimint_lnv2_common::KIND);
139
140 const KIND: EventKind = EventKind::from_static("complete-lightning-payment-succeeded");
141}
142
143pub fn compute_lnv2_stats(
147 all_events: &[PersistedLogEntry],
148) -> (StructuredPaymentEvents, StructuredPaymentEvents) {
149 let outgoing_start_events = filter_events_by_kind(
150 all_events,
151 fedimint_lnv2_common::KIND,
152 OutgoingPaymentStarted::KIND,
153 )
154 .collect::<Vec<_>>();
155 let outgoing_success_events = filter_events_by_kind(
156 all_events,
157 fedimint_lnv2_common::KIND,
158 OutgoingPaymentSucceeded::KIND,
159 )
160 .collect::<Vec<_>>();
161 let outgoing_failure_events = filter_events_by_kind(
162 all_events,
163 fedimint_lnv2_common::KIND,
164 OutgoingPaymentFailed::KIND,
165 )
166 .collect::<Vec<_>>();
167
168 let outgoing_success_stats =
169 join_events::<OutgoingPaymentStarted, OutgoingPaymentSucceeded, (u64, Amount)>(
170 &outgoing_start_events,
171 &outgoing_success_events,
172 |start_event, success_event, latency| {
173 if start_event.outgoing_contract.payment_image == success_event.payment_image {
174 start_event
175 .min_contract_amount
176 .checked_sub(start_event.invoice_amount)
177 .map(|fee| (latency, 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 |start_event, fail_event, latency| {
189 if start_event.outgoing_contract.payment_image == fail_event.payment_image {
190 Some(latency)
191 } else {
192 None
193 }
194 },
195 )
196 .collect::<Vec<_>>();
197
198 let incoming_start_events = filter_events_by_kind(
199 all_events,
200 fedimint_lnv2_common::KIND,
201 IncomingPaymentStarted::KIND,
202 )
203 .collect::<Vec<_>>();
204 let incoming_success_events = filter_events_by_kind(
205 all_events,
206 fedimint_lnv2_common::KIND,
207 IncomingPaymentSucceeded::KIND,
208 )
209 .collect::<Vec<_>>();
210 let incoming_failure_events = filter_events_by_kind(
211 all_events,
212 fedimint_lnv2_common::KIND,
213 IncomingPaymentFailed::KIND,
214 )
215 .collect::<Vec<_>>();
216
217 let incoming_success_stats =
218 join_events::<IncomingPaymentStarted, IncomingPaymentSucceeded, (u64, Amount)>(
219 &incoming_start_events,
220 &incoming_success_events,
221 |start_event, success_event, latency| {
222 if start_event.incoming_contract_commitment.payment_image
223 == success_event.payment_image
224 {
225 start_event
226 .invoice_amount
227 .checked_sub(start_event.incoming_contract_commitment.amount)
228 .map(|fee| (latency, fee))
229 } else {
230 None
231 }
232 },
233 )
234 .collect::<Vec<_>>();
235
236 let incoming_failure_stats = join_events::<IncomingPaymentStarted, IncomingPaymentFailed, u64>(
237 &incoming_start_events,
238 &incoming_failure_events,
239 |start_event, fail_event, latency| {
240 if start_event.incoming_contract_commitment.payment_image == fail_event.payment_image {
241 Some(latency)
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}