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