Skip to main content

fedimint_gateway_server/
rpc_server.rs

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