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