1use std::collections::BTreeMap;
2
3use bitcoin::address::NetworkUnchecked;
4use bitcoin::{Address, Txid};
5use fedimint_connectors::ServerResult;
6use fedimint_connectors::error::ServerError;
7use fedimint_core::PeerId;
8use fedimint_core::config::FederationId;
9use fedimint_core::invite_code::InviteCode;
10use fedimint_core::util::SafeUrl;
11use fedimint_gateway_common::{
12 ADDRESS_ENDPOINT, ADDRESS_RECHECK_ENDPOINT, BACKUP_ENDPOINT, BackupPayload,
13 CLOSE_CHANNELS_WITH_PEER_ENDPOINT, CONFIGURATION_ENDPOINT, CONNECT_FED_ENDPOINT,
14 CONNECT_PEER_ENDPOINT, CREATE_BOLT11_INVOICE_FOR_OPERATOR_ENDPOINT,
15 CREATE_BOLT12_OFFER_FOR_OPERATOR_ENDPOINT, ChannelInfo, CloseChannelsWithPeerRequest,
16 CloseChannelsWithPeerResponse, ConfigPayload, ConnectFedPayload, ConnectPeerRequest,
17 CreateInvoiceForOperatorPayload, CreateOfferPayload, CreateOfferResponse,
18 DepositAddressPayload, DepositAddressRecheckPayload, FEDERATION_STATUS_ENDPOINT,
19 FederationInfo, FederationStatusRequest, FederationStatusResponse, GATEWAY_INFO_ENDPOINT,
20 GET_BALANCES_ENDPOINT, GET_INVOICE_ENDPOINT, GET_LN_ONCHAIN_ADDRESS_ENDPOINT, GatewayBalances,
21 GatewayFedConfig, GatewayInfo, GetInvoiceRequest, GetInvoiceResponse, INVITE_CODES_ENDPOINT,
22 LEAVE_FED_ENDPOINT, LIST_CHANNELS_ENDPOINT, LIST_TRANSACTIONS_ENDPOINT, LeaveFedPayload,
23 ListTransactionsPayload, ListTransactionsResponse, MNEMONIC_ENDPOINT, MnemonicResponse,
24 OPEN_CHANNEL_ENDPOINT, OPEN_CHANNEL_WITH_PUSH_ENDPOINT, OpenChannelRequest,
25 PAY_INVOICE_FOR_OPERATOR_ENDPOINT, PAY_OFFER_FOR_OPERATOR_ENDPOINT, PAYMENT_LOG_ENDPOINT,
26 PAYMENT_SUMMARY_ENDPOINT, PEGIN_FROM_ONCHAIN_ENDPOINT, PayInvoiceForOperatorPayload,
27 PayOfferPayload, PayOfferResponse, PaymentLogPayload, PaymentLogResponse,
28 PaymentSummaryPayload, PaymentSummaryResponse, PeginFromOnchainPayload, RECEIVE_ECASH_ENDPOINT,
29 ReceiveEcashPayload, ReceiveEcashResponse, SEND_ONCHAIN_ENDPOINT, SET_CHANNEL_FEES_ENDPOINT,
30 SET_FEES_ENDPOINT, SET_PAYMENT_POLICY_ENDPOINT, SPEND_ECASH_ENDPOINT, STOP_ENDPOINT,
31 SendOnchainRequest, SetChannelFeesRequest, SetFeesPayload, SetMnemonicPayload,
32 SetPaymentPolicyPayload, SpendEcashPayload, SpendEcashResponse, WITHDRAW_ENDPOINT,
33 WITHDRAW_TO_ONCHAIN_ENDPOINT, WithdrawPayload, WithdrawResponse, WithdrawToOnchainPayload,
34};
35use fedimint_ln_common::Method;
36use fedimint_ln_common::client::GatewayApi;
37use lightning_invoice::Bolt11Invoice;
38
39pub async fn get_info(client: &GatewayApi, base_url: &SafeUrl) -> ServerResult<GatewayInfo> {
40 client
41 .request::<(), GatewayInfo>(base_url, Method::GET, GATEWAY_INFO_ENDPOINT, None)
42 .await
43}
44
45pub async fn get_federation_status(
52 client: &GatewayApi,
53 base_url: &SafeUrl,
54 federation_id: FederationId,
55) -> ServerResult<FederationStatusResponse> {
56 let status = client
57 .request::<_, FederationStatusResponse>(
58 base_url,
59 Method::POST,
60 FEDERATION_STATUS_ENDPOINT,
61 Some(FederationStatusRequest { federation_id }),
62 )
63 .await?;
64 validate_federation_status(status, federation_id)
65}
66
67fn validate_federation_status(
68 status: FederationStatusResponse,
69 federation_id: FederationId,
70) -> ServerResult<FederationStatusResponse> {
71 if status.federation_id() != federation_id {
72 return Err(ServerError::InvalidResponse(
73 "Gateway federation status response names a different federation".to_string(),
74 ));
75 }
76 Ok(status)
77}
78
79pub async fn get_config(
80 client: &GatewayApi,
81 base_url: &SafeUrl,
82 payload: ConfigPayload,
83) -> ServerResult<GatewayFedConfig> {
84 client
85 .request(
86 base_url,
87 Method::POST,
88 CONFIGURATION_ENDPOINT,
89 Some(payload),
90 )
91 .await
92}
93
94pub async fn get_deposit_address(
95 client: &GatewayApi,
96 base_url: &SafeUrl,
97 payload: DepositAddressPayload,
98) -> ServerResult<Address<NetworkUnchecked>> {
99 client
100 .request(base_url, Method::POST, ADDRESS_ENDPOINT, Some(payload))
101 .await
102}
103
104pub async fn pegin_from_onchain(
105 client: &GatewayApi,
106 base_url: &SafeUrl,
107 payload: PeginFromOnchainPayload,
108) -> ServerResult<Txid> {
109 client
110 .request(
111 base_url,
112 Method::POST,
113 PEGIN_FROM_ONCHAIN_ENDPOINT,
114 Some(payload),
115 )
116 .await
117}
118
119pub async fn withdraw(
120 client: &GatewayApi,
121 base_url: &SafeUrl,
122 payload: WithdrawPayload,
123) -> ServerResult<WithdrawResponse> {
124 client
125 .request(base_url, Method::POST, WITHDRAW_ENDPOINT, Some(payload))
126 .await
127}
128
129pub async fn withdraw_to_onchain(
130 client: &GatewayApi,
131 base_url: &SafeUrl,
132 payload: WithdrawToOnchainPayload,
133) -> ServerResult<WithdrawResponse> {
134 client
135 .request(
136 base_url,
137 Method::POST,
138 WITHDRAW_TO_ONCHAIN_ENDPOINT,
139 Some(payload),
140 )
141 .await
142}
143
144pub async fn connect_federation(
145 client: &GatewayApi,
146 base_url: &SafeUrl,
147 payload: ConnectFedPayload,
148) -> ServerResult<FederationInfo> {
149 client
150 .request(base_url, Method::POST, CONNECT_FED_ENDPOINT, Some(payload))
151 .await
152}
153
154pub async fn leave_federation(
155 client: &GatewayApi,
156 base_url: &SafeUrl,
157 payload: LeaveFedPayload,
158) -> ServerResult<FederationInfo> {
159 client
160 .request(base_url, Method::POST, LEAVE_FED_ENDPOINT, Some(payload))
161 .await
162}
163
164pub async fn backup(
165 client: &GatewayApi,
166 base_url: &SafeUrl,
167 payload: BackupPayload,
168) -> ServerResult<()> {
169 client
170 .request(base_url, Method::POST, BACKUP_ENDPOINT, Some(payload))
171 .await
172}
173
174pub async fn set_fees(
175 client: &GatewayApi,
176 base_url: &SafeUrl,
177 payload: SetFeesPayload,
178) -> ServerResult<()> {
179 client
180 .request(base_url, Method::POST, SET_FEES_ENDPOINT, Some(payload))
181 .await
182}
183
184pub async fn set_payment_policy(
185 client: &GatewayApi,
186 base_url: &SafeUrl,
187 payload: SetPaymentPolicyPayload,
188) -> ServerResult<()> {
189 client
190 .request(
191 base_url,
192 Method::POST,
193 SET_PAYMENT_POLICY_ENDPOINT,
194 Some(payload),
195 )
196 .await
197}
198
199pub async fn create_invoice_for_self(
200 client: &GatewayApi,
201 base_url: &SafeUrl,
202 payload: CreateInvoiceForOperatorPayload,
203) -> ServerResult<Bolt11Invoice> {
204 client
205 .request(
206 base_url,
207 Method::POST,
208 CREATE_BOLT11_INVOICE_FOR_OPERATOR_ENDPOINT,
209 Some(payload),
210 )
211 .await
212}
213
214pub async fn pay_invoice(
215 client: &GatewayApi,
216 base_url: &SafeUrl,
217 payload: PayInvoiceForOperatorPayload,
218) -> ServerResult<String> {
219 client
220 .request(
221 base_url,
222 Method::POST,
223 PAY_INVOICE_FOR_OPERATOR_ENDPOINT,
224 Some(payload),
225 )
226 .await
227}
228
229pub async fn get_ln_onchain_address(
230 client: &GatewayApi,
231 base_url: &SafeUrl,
232) -> ServerResult<Address<NetworkUnchecked>> {
233 client
234 .request::<(), Address<NetworkUnchecked>>(
235 base_url,
236 Method::GET,
237 GET_LN_ONCHAIN_ADDRESS_ENDPOINT,
238 None,
239 )
240 .await
241}
242
243pub async fn open_channel(
244 client: &GatewayApi,
245 base_url: &SafeUrl,
246 payload: OpenChannelRequest,
247) -> ServerResult<Txid> {
248 client
249 .request(base_url, Method::POST, OPEN_CHANNEL_ENDPOINT, Some(payload))
250 .await
251}
252
253pub async fn connect_peer(
254 client: &GatewayApi,
255 base_url: &SafeUrl,
256 payload: ConnectPeerRequest,
257) -> ServerResult<()> {
258 client
259 .request(base_url, Method::POST, CONNECT_PEER_ENDPOINT, Some(payload))
260 .await
261}
262
263pub async fn open_channel_with_push(
264 client: &GatewayApi,
265 base_url: &SafeUrl,
266 payload: OpenChannelRequest,
267) -> ServerResult<Txid> {
268 client
269 .request(
270 base_url,
271 Method::POST,
272 OPEN_CHANNEL_WITH_PUSH_ENDPOINT,
273 Some(payload),
274 )
275 .await
276}
277
278pub async fn close_channels_with_peer(
279 client: &GatewayApi,
280 base_url: &SafeUrl,
281 payload: CloseChannelsWithPeerRequest,
282) -> ServerResult<CloseChannelsWithPeerResponse> {
283 client
284 .request(
285 base_url,
286 Method::POST,
287 CLOSE_CHANNELS_WITH_PEER_ENDPOINT,
288 Some(payload),
289 )
290 .await
291}
292
293pub async fn list_channels(
294 client: &GatewayApi,
295 base_url: &SafeUrl,
296) -> ServerResult<Vec<ChannelInfo>> {
297 client
298 .request::<(), Vec<ChannelInfo>>(base_url, Method::GET, LIST_CHANNELS_ENDPOINT, None)
299 .await
300}
301
302pub async fn set_channel_fees(
303 client: &GatewayApi,
304 base_url: &SafeUrl,
305 payload: SetChannelFeesRequest,
306) -> ServerResult<()> {
307 client
308 .request(
309 base_url,
310 Method::POST,
311 SET_CHANNEL_FEES_ENDPOINT,
312 Some(payload),
313 )
314 .await
315}
316
317pub async fn send_onchain(
318 client: &GatewayApi,
319 base_url: &SafeUrl,
320 payload: SendOnchainRequest,
321) -> ServerResult<Txid> {
322 client
323 .request(base_url, Method::POST, SEND_ONCHAIN_ENDPOINT, Some(payload))
324 .await
325}
326
327pub async fn recheck_address(
328 client: &GatewayApi,
329 base_url: &SafeUrl,
330 payload: DepositAddressRecheckPayload,
331) -> ServerResult<serde_json::Value> {
332 client
333 .request(
334 base_url,
335 Method::POST,
336 ADDRESS_RECHECK_ENDPOINT,
337 Some(payload),
338 )
339 .await
340}
341
342pub async fn spend_ecash(
343 client: &GatewayApi,
344 base_url: &SafeUrl,
345 payload: SpendEcashPayload,
346) -> ServerResult<SpendEcashResponse> {
347 client
348 .request(base_url, Method::POST, SPEND_ECASH_ENDPOINT, Some(payload))
349 .await
350}
351
352pub async fn receive_ecash(
353 client: &GatewayApi,
354 base_url: &SafeUrl,
355 payload: ReceiveEcashPayload,
356) -> ServerResult<ReceiveEcashResponse> {
357 client
358 .request(
359 base_url,
360 Method::POST,
361 RECEIVE_ECASH_ENDPOINT,
362 Some(payload),
363 )
364 .await
365}
366
367pub async fn get_balances(
368 client: &GatewayApi,
369 base_url: &SafeUrl,
370) -> ServerResult<GatewayBalances> {
371 client
372 .request::<(), GatewayBalances>(base_url, Method::GET, GET_BALANCES_ENDPOINT, None)
373 .await
374}
375
376pub async fn get_mnemonic(
377 client: &GatewayApi,
378 base_url: &SafeUrl,
379) -> ServerResult<MnemonicResponse> {
380 client
381 .request::<(), MnemonicResponse>(base_url, Method::GET, MNEMONIC_ENDPOINT, None)
382 .await
383}
384
385pub async fn stop(client: &GatewayApi, base_url: &SafeUrl) -> ServerResult<()> {
386 client
387 .request::<(), ()>(base_url, Method::GET, STOP_ENDPOINT, None)
388 .await
389}
390
391pub async fn payment_log(
392 client: &GatewayApi,
393 base_url: &SafeUrl,
394 payload: PaymentLogPayload,
395) -> ServerResult<PaymentLogResponse> {
396 client
397 .request(base_url, Method::POST, PAYMENT_LOG_ENDPOINT, Some(payload))
398 .await
399}
400
401pub async fn payment_summary(
402 client: &GatewayApi,
403 base_url: &SafeUrl,
404 payload: PaymentSummaryPayload,
405) -> ServerResult<PaymentSummaryResponse> {
406 client
407 .request(
408 base_url,
409 Method::POST,
410 PAYMENT_SUMMARY_ENDPOINT,
411 Some(payload),
412 )
413 .await
414}
415
416pub async fn get_invoice(
417 client: &GatewayApi,
418 base_url: &SafeUrl,
419 payload: GetInvoiceRequest,
420) -> ServerResult<Option<GetInvoiceResponse>> {
421 client
422 .request(base_url, Method::POST, GET_INVOICE_ENDPOINT, Some(payload))
423 .await
424}
425
426pub async fn list_transactions(
427 client: &GatewayApi,
428 base_url: &SafeUrl,
429 payload: ListTransactionsPayload,
430) -> ServerResult<ListTransactionsResponse> {
431 client
432 .request(
433 base_url,
434 Method::POST,
435 LIST_TRANSACTIONS_ENDPOINT,
436 Some(payload),
437 )
438 .await
439}
440
441pub async fn create_offer(
442 client: &GatewayApi,
443 base_url: &SafeUrl,
444 payload: CreateOfferPayload,
445) -> ServerResult<CreateOfferResponse> {
446 client
447 .request(
448 base_url,
449 Method::POST,
450 CREATE_BOLT12_OFFER_FOR_OPERATOR_ENDPOINT,
451 Some(payload),
452 )
453 .await
454}
455
456pub async fn pay_offer(
457 client: &GatewayApi,
458 base_url: &SafeUrl,
459 payload: PayOfferPayload,
460) -> ServerResult<PayOfferResponse> {
461 client
462 .request(
463 base_url,
464 Method::POST,
465 PAY_OFFER_FOR_OPERATOR_ENDPOINT,
466 Some(payload),
467 )
468 .await
469}
470
471pub async fn set_mnemonic(
472 client: &GatewayApi,
473 base_url: &SafeUrl,
474 payload: SetMnemonicPayload,
475) -> ServerResult<()> {
476 client
477 .request(base_url, Method::POST, MNEMONIC_ENDPOINT, Some(payload))
478 .await
479}
480
481pub async fn get_invite_codes(
482 client: &GatewayApi,
483 base_url: &SafeUrl,
484) -> ServerResult<BTreeMap<FederationId, BTreeMap<PeerId, (String, InviteCode)>>> {
485 client
486 .request::<(), BTreeMap<FederationId, BTreeMap<PeerId, (String, InviteCode)>>>(
487 base_url,
488 Method::GET,
489 INVITE_CODES_ENDPOINT,
490 None,
491 )
492 .await
493}
494
495#[cfg(test)]
496mod tests;