1use std::collections::HashMap;
2use std::sync::Arc;
3
4use anyhow::anyhow;
5use axum::extract::{Path, Query, Request};
6use axum::http::{StatusCode, header};
7use axum::middleware::{self, Next};
8use axum::response::IntoResponse;
9use axum::routing::{get, post};
10use axum::{Extension, Json, Router};
11use bitcoin::hashes::sha256;
12use fedimint_core::config::FederationId;
13use fedimint_core::task::TaskGroup;
14use fedimint_core::util::FmtCompact;
15use fedimint_gateway_common::{
16 ADDRESS_ENDPOINT, ADDRESS_RECHECK_ENDPOINT, BACKUP_ENDPOINT, BackupPayload,
17 CLOSE_CHANNELS_WITH_PEER_ENDPOINT, CONFIGURATION_ENDPOINT, CONNECT_FED_ENDPOINT,
18 CONNECT_PEER_ENDPOINT, CREATE_BOLT11_INVOICE_FOR_OPERATOR_ENDPOINT,
19 CREATE_BOLT12_OFFER_FOR_OPERATOR_ENDPOINT, CloseChannelsWithPeerRequest, ConfigPayload,
20 ConnectFedPayload, ConnectPeerRequest, CreateInvoiceForOperatorPayload, CreateOfferPayload,
21 DepositAddressPayload, DepositAddressRecheckPayload, GATEWAY_INFO_ENDPOINT,
22 GET_BALANCES_ENDPOINT, GET_INVOICE_ENDPOINT, GET_LN_ONCHAIN_ADDRESS_ENDPOINT,
23 GetInvoiceRequest, INVITE_CODES_ENDPOINT, LEAVE_FED_ENDPOINT, LIST_CHANNELS_ENDPOINT,
24 LIST_TRANSACTIONS_ENDPOINT, LeaveFedPayload, ListTransactionsPayload, MNEMONIC_ENDPOINT,
25 OPEN_CHANNEL_ENDPOINT, OPEN_CHANNEL_WITH_PUSH_ENDPOINT, OpenChannelRequest,
26 PAY_INVOICE_FOR_OPERATOR_ENDPOINT, PAY_OFFER_FOR_OPERATOR_ENDPOINT, PAYMENT_LOG_ENDPOINT,
27 PAYMENT_SUMMARY_ENDPOINT, PEGIN_FROM_ONCHAIN_ENDPOINT, PayInvoiceForOperatorPayload,
28 PayOfferPayload, PaymentLogPayload, PaymentSummaryPayload, PeginFromOnchainPayload,
29 RECEIVE_ECASH_ENDPOINT, ReceiveEcashPayload, SEND_ONCHAIN_ENDPOINT, SET_CHANNEL_FEES_ENDPOINT,
30 SET_FEES_ENDPOINT, SPEND_ECASH_ENDPOINT, STOP_ENDPOINT, SendOnchainRequest,
31 SetChannelFeesRequest, SetFeesPayload, SetMnemonicPayload, SpendEcashPayload, V1_API_ENDPOINT,
32 WITHDRAW_ENDPOINT, WITHDRAW_TO_ONCHAIN_ENDPOINT, WithdrawPayload, WithdrawToOnchainPayload,
33};
34use fedimint_gateway_ui::IAdminGateway;
35use fedimint_ln_common::gateway_endpoint_constants::{
36 GET_GATEWAY_ID_ENDPOINT, PAY_INVOICE_ENDPOINT,
37};
38use fedimint_lnurl::LnurlResponse;
39use fedimint_lnv2_common::endpoint_constants::{
40 CREATE_BOLT11_INVOICE_ENDPOINT, ROUTING_INFO_ENDPOINT, SEND_PAYMENT_ENDPOINT,
41};
42use fedimint_lnv2_common::gateway_api::{CreateBolt11InvoicePayload, SendPaymentPayload};
43use fedimint_logging::LOG_GATEWAY;
44use hex::ToHex;
45use serde::de::DeserializeOwned;
46use serde_json::json;
47use tokio::net::TcpListener;
48use tower_http::cors::CorsLayer;
49use tracing::{info, instrument, warn};
50
51use crate::error::{GatewayError, LnurlError};
52use crate::iroh_server::{Handlers, start_iroh_endpoint};
53use crate::{Gateway, GatewayState};
54
55const LIQUIDITY_MANAGER_ROUTES: [&str; 21] = [
58 ADDRESS_ENDPOINT,
59 ADDRESS_RECHECK_ENDPOINT,
60 CLOSE_CHANNELS_WITH_PEER_ENDPOINT,
61 CONFIGURATION_ENDPOINT,
62 CONNECT_PEER_ENDPOINT,
63 CREATE_BOLT11_INVOICE_FOR_OPERATOR_ENDPOINT,
64 CREATE_BOLT12_OFFER_FOR_OPERATOR_ENDPOINT,
65 GATEWAY_INFO_ENDPOINT,
66 GET_BALANCES_ENDPOINT,
67 GET_INVOICE_ENDPOINT,
68 GET_LN_ONCHAIN_ADDRESS_ENDPOINT,
69 INVITE_CODES_ENDPOINT,
70 LIST_CHANNELS_ENDPOINT,
71 LIST_TRANSACTIONS_ENDPOINT,
72 OPEN_CHANNEL_ENDPOINT,
73 PAYMENT_LOG_ENDPOINT,
74 PAYMENT_SUMMARY_ENDPOINT,
75 PEGIN_FROM_ONCHAIN_ENDPOINT,
76 SET_CHANNEL_FEES_ENDPOINT,
77 SET_FEES_ENDPOINT,
78 WITHDRAW_TO_ONCHAIN_ENDPOINT,
79];
80
81pub async fn run_webserver(
83 gateway: Arc<Gateway>,
84 mut mnemonic_receiver: tokio::sync::broadcast::Receiver<()>,
85) -> anyhow::Result<()> {
86 let task_group = gateway.task_group.clone();
87 let mut handlers = Handlers::new();
88
89 let routes = routes(gateway.clone(), task_group.clone(), &mut handlers);
90 let ui_routes = fedimint_gateway_ui::router(gateway.clone())
96 .layer(middleware::from_fn(not_configured_middleware))
97 .layer(Extension(gateway.clone()));
98 let api_v1 = Router::new()
99 .nest(&format!("/{V1_API_ENDPOINT}"), routes.clone())
100 .merge(routes)
102 .merge(ui_routes);
103
104 let handle = task_group.make_handle();
105 let shutdown_rx = handle.make_shutdown_rx();
106 let listener = TcpListener::bind(&gateway.listen).await?;
107 let serve = axum::serve(listener, api_v1.into_make_service());
108 task_group.spawn("Gateway Webserver", |_| async {
109 let graceful = serve.with_graceful_shutdown(async {
110 shutdown_rx.await;
111 });
112
113 match graceful.await {
114 Err(err) => {
115 warn!(target: LOG_GATEWAY, err = %err.fmt_compact(), "Error shutting down gatewayd webserver");
116 }
117 _ => {
118 info!(target: LOG_GATEWAY, "Successfully shutdown webserver");
119 }
120 }
121 });
122 info!(target: LOG_GATEWAY, listen = %gateway.listen, "Successfully started webserver");
123
124 if let GatewayState::NotConfigured { .. } = gateway.get_state().await {
127 info!(target: LOG_GATEWAY, "Waiting for the mnemonic to be set before starting iroh loop.");
128 let _ = mnemonic_receiver.recv().await;
129 }
130
131 start_iroh_endpoint(&gateway, task_group, Arc::new(handlers)).await?;
132
133 Ok(())
134}
135
136fn strip_v1_prefix(path: &str) -> &str {
140 match path.strip_prefix(&format!("/{V1_API_ENDPOINT}")) {
141 Some(stripped) if stripped.starts_with('/') => stripped,
142 _ => path,
143 }
144}
145
146fn extract_bearer_token(request: &Request) -> Result<String, StatusCode> {
148 let headers = request.headers();
149 let auth_header = headers.get(header::AUTHORIZATION);
150 if let Some(header_value) = auth_header {
151 let auth_str = header_value
152 .to_str()
153 .map_err(|_| StatusCode::UNAUTHORIZED)?;
154 let token = auth_str.trim_start_matches("Bearer ").to_string();
155 return Ok(token);
156 }
157
158 Err(StatusCode::UNAUTHORIZED)
159}
160
161async fn not_configured_middleware(
162 Extension(gateway): Extension<Arc<Gateway>>,
163 request: Request,
164 next: Next,
165) -> Result<impl IntoResponse, StatusCode> {
166 if matches!(
167 gateway.get_state().await,
168 GatewayState::NotConfigured { .. }
169 ) {
170 let method = request.method().clone();
171 let path = request.uri().path();
172
173 let is_mnemonic_api =
175 method == axum::http::Method::POST && strip_v1_prefix(path) == MNEMONIC_ENDPOINT;
176
177 let is_setup_route = fedimint_gateway_ui::is_allowed_setup_route(path);
178
179 if !is_mnemonic_api && !is_setup_route {
180 return Err(StatusCode::NOT_FOUND);
181 }
182 }
183
184 Ok(next.run(request).await)
185}
186
187async fn auth_middleware(
191 Extension(gateway): Extension<Arc<Gateway>>,
192 request: Request,
193 next: Next,
194) -> Result<impl IntoResponse, StatusCode> {
195 let token = extract_bearer_token(&request)?;
196 if bcrypt::verify(token.clone(), &gateway.bcrypt_password_hash)
197 .expect("Bcrypt hash is valid since we just stringified it")
198 {
199 return Ok(next.run(request).await);
200 }
201
202 if let Some(liquidity_manager_password_hash) = &gateway.bcrypt_liquidity_manager_password_hash
204 && bcrypt::verify(token, liquidity_manager_password_hash)
205 .expect("Bcrypt hash is valid since we just stringified it")
206 {
207 let path = strip_v1_prefix(request.uri().path());
208
209 if !LIQUIDITY_MANAGER_ROUTES.contains(&path) {
210 return Err(StatusCode::UNAUTHORIZED);
211 }
212
213 return Ok(next.run(request).await);
214 }
215
216 Err(StatusCode::UNAUTHORIZED)
217}
218
219fn register_get_handler<F, Fut>(
222 handlers: &mut Handlers,
223 route: &str,
224 func: F,
225 is_authenticated: bool,
226 router: Router,
227) -> Router
228where
229 F: Fn(Extension<Arc<Gateway>>) -> Fut + Clone + Send + Sync + 'static,
230 Fut: Future<Output = Result<Json<serde_json::Value>, GatewayError>> + Send + 'static,
231{
232 handlers.add_handler(route, func.clone(), is_authenticated);
233 router.route(route, get(func))
234}
235
236fn register_post_handler<P, F, Fut>(
239 handlers: &mut Handlers,
240 route: &str,
241 func: F,
242 is_authenticated: bool,
243 router: Router,
244) -> Router
245where
246 P: DeserializeOwned + Send + 'static,
247 F: Fn(Extension<Arc<Gateway>>, Json<P>) -> Fut + Clone + Send + Sync + 'static,
248 Fut: Future<Output = Result<Json<serde_json::Value>, GatewayError>> + Send + 'static,
249{
250 handlers.add_handler_with_payload(route, func.clone(), is_authenticated);
251 router.route(route, post(func))
252}
253
254fn lnv1_routes(handlers: &mut Handlers) -> Router {
256 let router = Router::new();
257 let router = register_post_handler(handlers, PAY_INVOICE_ENDPOINT, pay_invoice, false, router);
258 register_get_handler(
259 handlers,
260 GET_GATEWAY_ID_ENDPOINT,
261 get_gateway_id,
262 false,
263 router,
264 )
265}
266
267fn lnv2_routes(handlers: &mut Handlers) -> Router {
269 let router = Router::new();
270 let router = register_post_handler(
271 handlers,
272 ROUTING_INFO_ENDPOINT,
273 routing_info_v2,
274 false,
275 router,
276 );
277 let router = register_post_handler(
278 handlers,
279 SEND_PAYMENT_ENDPOINT,
280 pay_bolt11_invoice_v2,
281 false,
282 router,
283 );
284 let router = register_post_handler(
285 handlers,
286 CREATE_BOLT11_INVOICE_ENDPOINT,
287 create_bolt11_invoice_v2,
288 false,
289 router,
290 );
291 router.route("/verify/{payment_hash}", get(verify_bolt11_preimage_v2_get))
293}
294
295fn routes(gateway: Arc<Gateway>, task_group: TaskGroup, handlers: &mut Handlers) -> Router {
301 let mut public_routes = register_post_handler(
303 handlers,
304 RECEIVE_ECASH_ENDPOINT,
305 receive_ecash,
306 false,
307 Router::new(),
308 );
309 public_routes = public_routes.merge(lnv1_routes(handlers));
310 public_routes = public_routes.merge(lnv2_routes(handlers));
311
312 let is_authenticated = true;
314 let authenticated_routes = Router::new();
315 let authenticated_routes = register_post_handler(
316 handlers,
317 ADDRESS_ENDPOINT,
318 address,
319 is_authenticated,
320 authenticated_routes,
321 );
322 let authenticated_routes = register_post_handler(
323 handlers,
324 WITHDRAW_ENDPOINT,
325 withdraw,
326 is_authenticated,
327 authenticated_routes,
328 );
329 let authenticated_routes = register_post_handler(
330 handlers,
331 WITHDRAW_TO_ONCHAIN_ENDPOINT,
332 withdraw_to_onchain,
333 is_authenticated,
334 authenticated_routes,
335 );
336 let authenticated_routes = register_post_handler(
337 handlers,
338 PEGIN_FROM_ONCHAIN_ENDPOINT,
339 pegin_from_onchain,
340 is_authenticated,
341 authenticated_routes,
342 );
343 let authenticated_routes = register_post_handler(
344 handlers,
345 CONNECT_FED_ENDPOINT,
346 connect_fed,
347 is_authenticated,
348 authenticated_routes,
349 );
350 let authenticated_routes = register_post_handler(
351 handlers,
352 LEAVE_FED_ENDPOINT,
353 leave_fed,
354 is_authenticated,
355 authenticated_routes,
356 );
357 let authenticated_routes = register_post_handler(
358 handlers,
359 BACKUP_ENDPOINT,
360 backup,
361 is_authenticated,
362 authenticated_routes,
363 );
364 let authenticated_routes = register_post_handler(
365 handlers,
366 CREATE_BOLT11_INVOICE_FOR_OPERATOR_ENDPOINT,
367 create_invoice_for_operator,
368 is_authenticated,
369 authenticated_routes,
370 );
371 let authenticated_routes = register_post_handler(
372 handlers,
373 CREATE_BOLT12_OFFER_FOR_OPERATOR_ENDPOINT,
374 create_offer_for_operator,
375 is_authenticated,
376 authenticated_routes,
377 );
378 let authenticated_routes = register_post_handler(
379 handlers,
380 PAY_INVOICE_FOR_OPERATOR_ENDPOINT,
381 pay_invoice_operator,
382 is_authenticated,
383 authenticated_routes,
384 );
385 let authenticated_routes = register_post_handler(
386 handlers,
387 PAY_OFFER_FOR_OPERATOR_ENDPOINT,
388 pay_offer_operator,
389 is_authenticated,
390 authenticated_routes,
391 );
392 let authenticated_routes = register_post_handler(
393 handlers,
394 GET_INVOICE_ENDPOINT,
395 get_invoice,
396 is_authenticated,
397 authenticated_routes,
398 );
399 let authenticated_routes = register_get_handler(
400 handlers,
401 GET_LN_ONCHAIN_ADDRESS_ENDPOINT,
402 get_ln_onchain_address,
403 is_authenticated,
404 authenticated_routes,
405 );
406 let authenticated_routes = register_post_handler(
407 handlers,
408 OPEN_CHANNEL_ENDPOINT,
409 open_channel,
410 is_authenticated,
411 authenticated_routes,
412 );
413 let authenticated_routes = register_post_handler(
414 handlers,
415 CONNECT_PEER_ENDPOINT,
416 connect_peer,
417 is_authenticated,
418 authenticated_routes,
419 );
420 let authenticated_routes = register_post_handler(
421 handlers,
422 OPEN_CHANNEL_WITH_PUSH_ENDPOINT,
423 open_channel_with_push,
424 is_authenticated,
425 authenticated_routes,
426 );
427 let authenticated_routes = register_post_handler(
428 handlers,
429 CLOSE_CHANNELS_WITH_PEER_ENDPOINT,
430 close_channels_with_peer,
431 is_authenticated,
432 authenticated_routes,
433 );
434 let authenticated_routes = register_get_handler(
435 handlers,
436 LIST_CHANNELS_ENDPOINT,
437 list_channels,
438 is_authenticated,
439 authenticated_routes,
440 );
441 let authenticated_routes = register_post_handler(
442 handlers,
443 SET_CHANNEL_FEES_ENDPOINT,
444 set_channel_fees,
445 is_authenticated,
446 authenticated_routes,
447 );
448 let authenticated_routes = register_post_handler(
449 handlers,
450 LIST_TRANSACTIONS_ENDPOINT,
451 list_transactions,
452 is_authenticated,
453 authenticated_routes,
454 );
455 let authenticated_routes = register_post_handler(
456 handlers,
457 SEND_ONCHAIN_ENDPOINT,
458 send_onchain,
459 is_authenticated,
460 authenticated_routes,
461 );
462 let authenticated_routes = register_post_handler(
463 handlers,
464 ADDRESS_RECHECK_ENDPOINT,
465 recheck_address,
466 is_authenticated,
467 authenticated_routes,
468 );
469 let authenticated_routes = register_get_handler(
470 handlers,
471 GET_BALANCES_ENDPOINT,
472 get_balances,
473 is_authenticated,
474 authenticated_routes,
475 );
476 let authenticated_routes = register_post_handler(
477 handlers,
478 SPEND_ECASH_ENDPOINT,
479 spend_ecash,
480 is_authenticated,
481 authenticated_routes,
482 );
483 let authenticated_routes = register_get_handler(
484 handlers,
485 MNEMONIC_ENDPOINT,
486 mnemonic,
487 is_authenticated,
488 authenticated_routes,
489 );
490 let authenticated_routes = authenticated_routes.route(STOP_ENDPOINT, get(stop));
492 let authenticated_routes = register_post_handler(
493 handlers,
494 PAYMENT_LOG_ENDPOINT,
495 payment_log,
496 is_authenticated,
497 authenticated_routes,
498 );
499 let authenticated_routes = register_post_handler(
500 handlers,
501 PAYMENT_SUMMARY_ENDPOINT,
502 payment_summary,
503 is_authenticated,
504 authenticated_routes,
505 );
506 let authenticated_routes = register_post_handler(
507 handlers,
508 SET_FEES_ENDPOINT,
509 set_fees,
510 is_authenticated,
511 authenticated_routes,
512 );
513 let authenticated_routes = register_post_handler(
514 handlers,
515 CONFIGURATION_ENDPOINT,
516 configuration,
517 is_authenticated,
518 authenticated_routes,
519 );
520 let authenticated_routes = register_get_handler(
521 handlers,
522 GATEWAY_INFO_ENDPOINT,
523 info,
524 is_authenticated,
525 authenticated_routes,
526 );
527 let authenticated_routes = register_post_handler(
528 handlers,
529 MNEMONIC_ENDPOINT,
530 set_mnemonic,
531 is_authenticated,
532 authenticated_routes,
533 );
534 let authenticated_routes = register_get_handler(
535 handlers,
536 INVITE_CODES_ENDPOINT,
537 invite_codes,
538 is_authenticated,
539 authenticated_routes,
540 );
541 let authenticated_routes = authenticated_routes.layer(middleware::from_fn(auth_middleware));
542
543 Router::new()
544 .merge(public_routes)
545 .merge(authenticated_routes)
546 .layer(middleware::from_fn(not_configured_middleware))
547 .layer(Extension(gateway))
548 .layer(Extension(task_group))
549 .layer(CorsLayer::permissive())
550}
551
552#[instrument(target = LOG_GATEWAY, skip_all, err)]
554async fn info(
555 Extension(gateway): Extension<Arc<Gateway>>,
556) -> Result<Json<serde_json::Value>, GatewayError> {
557 let info = gateway.handle_get_info().await?;
558 Ok(Json(json!(info)))
559}
560
561#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
563async fn configuration(
564 Extension(gateway): Extension<Arc<Gateway>>,
565 Json(payload): Json<ConfigPayload>,
566) -> Result<Json<serde_json::Value>, GatewayError> {
567 let gateway_fed_config = gateway
568 .handle_get_federation_config(payload.federation_id)
569 .await?;
570 Ok(Json(json!(gateway_fed_config)))
571}
572
573#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
575async fn address(
576 Extension(gateway): Extension<Arc<Gateway>>,
577 Json(payload): Json<DepositAddressPayload>,
578) -> Result<Json<serde_json::Value>, GatewayError> {
579 let address = gateway.handle_address_msg(payload).await?;
580 Ok(Json(json!(address)))
581}
582
583#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
585async fn pegin_from_onchain(
586 Extension(gateway): Extension<Arc<Gateway>>,
587 Json(payload): Json<PeginFromOnchainPayload>,
588) -> Result<Json<serde_json::Value>, GatewayError> {
589 let address = gateway.handle_pegin_from_onchain_msg(payload).await?;
590 Ok(Json(json!(address)))
591}
592
593#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
595async fn withdraw(
596 Extension(gateway): Extension<Arc<Gateway>>,
597 Json(payload): Json<WithdrawPayload>,
598) -> Result<Json<serde_json::Value>, GatewayError> {
599 let txid = gateway.handle_withdraw_msg(payload).await?;
600 Ok(Json(json!(txid)))
601}
602
603#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
605async fn withdraw_to_onchain(
606 Extension(gateway): Extension<Arc<Gateway>>,
607 Json(payload): Json<WithdrawToOnchainPayload>,
608) -> Result<Json<serde_json::Value>, GatewayError> {
609 let txid = gateway.handle_withdraw_to_onchain_msg(payload).await?;
610 Ok(Json(json!(txid)))
611}
612
613#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
614async fn create_invoice_for_operator(
615 Extension(gateway): Extension<Arc<Gateway>>,
616 Json(payload): Json<CreateInvoiceForOperatorPayload>,
617) -> Result<Json<serde_json::Value>, GatewayError> {
618 let invoice = gateway
619 .handle_create_invoice_for_operator_msg(payload)
620 .await?;
621 Ok(Json(json!(invoice)))
622}
623
624#[instrument(target = LOG_GATEWAY, skip_all, err)]
625async fn pay_invoice_operator(
626 Extension(gateway): Extension<Arc<Gateway>>,
627 Json(payload): Json<PayInvoiceForOperatorPayload>,
628) -> Result<Json<serde_json::Value>, GatewayError> {
629 let preimage = gateway.handle_pay_invoice_for_operator_msg(payload).await?;
630 Ok(Json(json!(preimage.0.encode_hex::<String>())))
631}
632
633#[instrument(target = LOG_GATEWAY, skip_all, err)]
634async fn pay_invoice(
635 Extension(gateway): Extension<Arc<Gateway>>,
636 Json(payload): Json<fedimint_ln_client::pay::PayInvoicePayload>,
637) -> Result<Json<serde_json::Value>, GatewayError> {
638 let preimage = gateway.handle_pay_invoice_msg(payload).await?;
639 Ok(Json(json!(preimage.0.encode_hex::<String>())))
640}
641
642#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
644async fn connect_fed(
645 Extension(gateway): Extension<Arc<Gateway>>,
646 Json(payload): Json<ConnectFedPayload>,
647) -> Result<Json<serde_json::Value>, GatewayError> {
648 let fed = gateway.handle_connect_federation(payload).await?;
649 Ok(Json(json!(fed)))
650}
651
652#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
654async fn leave_fed(
655 Extension(gateway): Extension<Arc<Gateway>>,
656 Json(payload): Json<LeaveFedPayload>,
657) -> Result<Json<serde_json::Value>, GatewayError> {
658 let fed = gateway.handle_leave_federation(payload).await?;
659 Ok(Json(json!(fed)))
660}
661
662#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
664async fn backup(
665 Extension(gateway): Extension<Arc<Gateway>>,
666 Json(payload): Json<BackupPayload>,
667) -> Result<Json<serde_json::Value>, GatewayError> {
668 gateway.handle_backup_msg(payload).await?;
669 Ok(Json(json!(())))
670}
671
672#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
673async fn set_fees(
674 Extension(gateway): Extension<Arc<Gateway>>,
675 Json(payload): Json<SetFeesPayload>,
676) -> Result<Json<serde_json::Value>, GatewayError> {
677 gateway.handle_set_fees_msg(payload).await?;
678 Ok(Json(json!(())))
679}
680
681#[instrument(target = LOG_GATEWAY, skip_all, err)]
682async fn get_ln_onchain_address(
683 Extension(gateway): Extension<Arc<Gateway>>,
684) -> Result<Json<serde_json::Value>, GatewayError> {
685 let address = gateway.handle_get_ln_onchain_address_msg().await?;
686 Ok(Json(json!(address.to_string())))
687}
688
689#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
690async fn open_channel(
691 Extension(gateway): Extension<Arc<Gateway>>,
692 Json(mut payload): Json<OpenChannelRequest>,
693) -> Result<Json<serde_json::Value>, GatewayError> {
694 payload.push_amount_sats = 0;
695 let funding_txid = gateway.handle_open_channel_msg(payload).await?;
696 Ok(Json(json!(funding_txid)))
697}
698
699#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
700async fn connect_peer(
701 Extension(gateway): Extension<Arc<Gateway>>,
702 Json(payload): Json<ConnectPeerRequest>,
703) -> Result<Json<serde_json::Value>, GatewayError> {
704 gateway.handle_connect_peer_msg(payload).await?;
705 Ok(Json(json!(())))
706}
707
708#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
709async fn open_channel_with_push(
710 Extension(gateway): Extension<Arc<Gateway>>,
711 Json(payload): Json<OpenChannelRequest>,
712) -> Result<Json<serde_json::Value>, GatewayError> {
713 let funding_txid = gateway.handle_open_channel_msg(payload).await?;
714 Ok(Json(json!(funding_txid)))
715}
716
717#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
718async fn close_channels_with_peer(
719 Extension(gateway): Extension<Arc<Gateway>>,
720 Json(payload): Json<CloseChannelsWithPeerRequest>,
721) -> Result<Json<serde_json::Value>, GatewayError> {
722 let response = gateway.handle_close_channels_with_peer_msg(payload).await?;
723 Ok(Json(json!(response)))
724}
725
726#[instrument(target = LOG_GATEWAY, skip_all, err)]
727async fn list_channels(
728 Extension(gateway): Extension<Arc<Gateway>>,
729) -> Result<Json<serde_json::Value>, GatewayError> {
730 let channels = gateway.handle_list_channels_msg().await?;
731 Ok(Json(json!(channels)))
732}
733
734#[instrument(target = LOG_GATEWAY, skip_all, err, fields(?payload))]
735async fn set_channel_fees(
736 Extension(gateway): Extension<Arc<Gateway>>,
737 Json(payload): Json<SetChannelFeesRequest>,
738) -> Result<Json<serde_json::Value>, GatewayError> {
739 gateway.handle_set_channel_fees_msg(payload).await?;
740 Ok(Json(json!(())))
741}
742
743#[instrument(target = LOG_GATEWAY, skip_all, err)]
744async fn send_onchain(
745 Extension(gateway): Extension<Arc<Gateway>>,
746 Json(payload): Json<SendOnchainRequest>,
747) -> Result<Json<serde_json::Value>, GatewayError> {
748 let txid = gateway.handle_send_onchain_msg(payload).await?;
749 Ok(Json(json!(txid)))
750}
751
752#[instrument(target = LOG_GATEWAY, skip_all, err)]
753async fn recheck_address(
754 Extension(gateway): Extension<Arc<Gateway>>,
755 Json(payload): Json<DepositAddressRecheckPayload>,
756) -> Result<Json<serde_json::Value>, GatewayError> {
757 gateway.handle_recheck_address_msg(payload).await?;
758 Ok(Json(json!({})))
759}
760
761#[instrument(target = LOG_GATEWAY, skip_all, err)]
762async fn get_balances(
763 Extension(gateway): Extension<Arc<Gateway>>,
764) -> Result<Json<serde_json::Value>, GatewayError> {
765 let balances = gateway.handle_get_balances_msg().await?;
766 Ok(Json(json!(balances)))
767}
768
769#[instrument(target = LOG_GATEWAY, skip_all, err)]
770async fn get_gateway_id(
771 Extension(gateway): Extension<Arc<Gateway>>,
772) -> Result<Json<serde_json::Value>, GatewayError> {
773 Ok(Json(json!(gateway.http_gateway_id().await)))
774}
775
776#[instrument(target = LOG_GATEWAY, skip_all, err)]
777async fn routing_info_v2(
778 Extension(gateway): Extension<Arc<Gateway>>,
779 Json(federation_id): Json<FederationId>,
780) -> Result<Json<serde_json::Value>, GatewayError> {
781 let routing_info = gateway.routing_info_v2(&federation_id).await?;
782 Ok(Json(json!(routing_info)))
783}
784
785#[instrument(target = LOG_GATEWAY, skip_all, err)]
786async fn pay_bolt11_invoice_v2(
787 Extension(gateway): Extension<Arc<Gateway>>,
788 Json(payload): Json<SendPaymentPayload>,
789) -> Result<Json<serde_json::Value>, GatewayError> {
790 let payment_result = gateway.send_payment_v2(payload).await?;
791 Ok(Json(json!(payment_result)))
792}
793
794#[instrument(target = LOG_GATEWAY, skip_all, err)]
795async fn create_bolt11_invoice_v2(
796 Extension(gateway): Extension<Arc<Gateway>>,
797 Json(payload): Json<CreateBolt11InvoicePayload>,
798) -> Result<Json<serde_json::Value>, GatewayError> {
799 let invoice = gateway.create_bolt11_invoice_v2(payload).await?;
800 Ok(Json(json!(invoice)))
801}
802
803pub(crate) async fn verify_bolt11_preimage_v2_get(
804 Extension(gateway): Extension<Arc<Gateway>>,
805 Path(payment_hash): Path<sha256::Hash>,
806 Query(query): Query<HashMap<String, String>>,
807) -> Result<Json<serde_json::Value>, GatewayError> {
808 let response = gateway
809 .verify_bolt11_preimage_v2(payment_hash, query.contains_key("wait"))
810 .await
811 .map_err(|e| LnurlError::internal(anyhow!(e)))?;
812
813 Ok(Json(json!(LnurlResponse::Ok(response))))
814}
815
816#[instrument(target = LOG_GATEWAY, skip_all, err)]
817async fn spend_ecash(
818 Extension(gateway): Extension<Arc<Gateway>>,
819 Json(payload): Json<SpendEcashPayload>,
820) -> Result<Json<serde_json::Value>, GatewayError> {
821 Ok(Json(json!(gateway.handle_spend_ecash_msg(payload).await?)))
822}
823
824#[instrument(target = LOG_GATEWAY, skip_all, err)]
825async fn receive_ecash(
826 Extension(gateway): Extension<Arc<Gateway>>,
827 Json(payload): Json<ReceiveEcashPayload>,
828) -> Result<Json<serde_json::Value>, GatewayError> {
829 Ok(Json(json!(
830 gateway.handle_receive_ecash_msg(payload).await?
831 )))
832}
833
834#[instrument(target = LOG_GATEWAY, skip_all, err)]
835async fn mnemonic(
836 Extension(gateway): Extension<Arc<Gateway>>,
837) -> Result<Json<serde_json::Value>, GatewayError> {
838 let words = gateway.handle_mnemonic_msg().await?;
839 Ok(Json(json!(words)))
840}
841
842#[instrument(target = LOG_GATEWAY, skip_all, err)]
843async fn set_mnemonic(
844 Extension(gateway): Extension<Arc<Gateway>>,
845 Json(payload): Json<SetMnemonicPayload>,
846) -> Result<Json<serde_json::Value>, GatewayError> {
847 gateway.handle_set_mnemonic_msg(payload).await?;
848 Ok(Json(json!(())))
849}
850
851#[instrument(target = LOG_GATEWAY, skip_all, err)]
852pub(crate) async fn stop(
853 Extension(task_group): Extension<TaskGroup>,
854 Extension(gateway): Extension<Arc<Gateway>>,
855) -> Result<Json<serde_json::Value>, GatewayError> {
856 gateway.handle_shutdown_msg(task_group).await?;
857 Ok(Json(json!(())))
858}
859
860#[instrument(target = LOG_GATEWAY, skip_all, err)]
867async fn payment_log(
868 Extension(gateway): Extension<Arc<Gateway>>,
869 Json(payload): Json<PaymentLogPayload>,
870) -> Result<Json<serde_json::Value>, GatewayError> {
871 let payment_log = gateway.handle_payment_log_msg(payload).await?;
872 Ok(Json(json!(payment_log)))
873}
874
875#[instrument(target = LOG_GATEWAY, skip_all, err)]
876async fn payment_summary(
877 Extension(gateway): Extension<Arc<Gateway>>,
878 Json(payload): Json<PaymentSummaryPayload>,
879) -> Result<Json<serde_json::Value>, GatewayError> {
880 let payment_summary = gateway.handle_payment_summary_msg(payload).await?;
881 Ok(Json(json!(payment_summary)))
882}
883
884#[instrument(target = LOG_GATEWAY, skip_all, err)]
885async fn get_invoice(
886 Extension(gateway): Extension<Arc<Gateway>>,
887 Json(payload): Json<GetInvoiceRequest>,
888) -> Result<Json<serde_json::Value>, GatewayError> {
889 let invoice = gateway.handle_get_invoice_msg(payload).await?;
890 Ok(Json(json!(invoice)))
891}
892
893#[instrument(target = LOG_GATEWAY, skip_all, err)]
894async fn list_transactions(
895 Extension(gateway): Extension<Arc<Gateway>>,
896 Json(payload): Json<ListTransactionsPayload>,
897) -> Result<Json<serde_json::Value>, GatewayError> {
898 let transactions = gateway.handle_list_transactions_msg(payload).await?;
899 Ok(Json(json!(transactions)))
900}
901
902#[instrument(target = LOG_GATEWAY, skip_all, err)]
903async fn create_offer_for_operator(
904 Extension(gateway): Extension<Arc<Gateway>>,
905 Json(payload): Json<CreateOfferPayload>,
906) -> Result<Json<serde_json::Value>, GatewayError> {
907 let offer = gateway
908 .handle_create_offer_for_operator_msg(payload)
909 .await?;
910 Ok(Json(json!(offer)))
911}
912
913#[instrument(target = LOG_GATEWAY, skip_all, err)]
914async fn pay_offer_operator(
915 Extension(gateway): Extension<Arc<Gateway>>,
916 Json(payload): Json<PayOfferPayload>,
917) -> Result<Json<serde_json::Value>, GatewayError> {
918 let response = gateway.handle_pay_offer_for_operator_msg(payload).await?;
919 Ok(Json(json!(response)))
920}
921
922#[instrument(target = LOG_GATEWAY, skip_all, err)]
923async fn invite_codes(
924 Extension(gateway): Extension<Arc<Gateway>>,
925) -> Result<Json<serde_json::Value>, GatewayError> {
926 let invite_codes = gateway.handle_export_invite_codes().await;
927 Ok(Json(json!(invite_codes)))
928}
929
930#[cfg(test)]
931mod tests {
932 use super::*;
933
934 #[test]
935 fn strip_v1_prefix_covers_both_api_mounts() {
936 for route in LIQUIDITY_MANAGER_ROUTES {
937 assert_eq!(strip_v1_prefix(route), route);
938 assert_eq!(
939 strip_v1_prefix(&format!("/{V1_API_ENDPOINT}{route}")),
940 route
941 );
942 }
943 }
944
945 #[test]
946 fn strip_v1_prefix_only_strips_a_full_leading_segment() {
947 assert_eq!(strip_v1_prefix("/v1"), "/v1");
948 assert_eq!(strip_v1_prefix("/v1x/address"), "/v1x/address");
949 assert_eq!(strip_v1_prefix("/v1/v1/address"), "/v1/address");
950 }
951}