Skip to main content

lexe_api_core/
def.rs

1//! # API Definitions
2//!
3//! This module, as closely as possible, defines the various APIs exposed by
4//! different services to different clients. Although we do not have
5//! compile-time guarantees that the services exposed exactly match the
6//! definitions below, it is straightforward to compare the Axum routers and
7//! handlers with the definitions below to ensure consistency.
8//!
9//! ## Guidelines
10//!
11//! All API requests and responses should return structs for upgradeability,
12//! e.g. [`UserPkStruct`] instead of [`UserPk`].
13//!
14//! If an API method takes or returns nothing, make the type [`Empty`] and NOT
15//! `()` (unit type). Using `()` makes it impossible to add optional fields in a
16//! backwards-compatible way.
17//!
18//! Each endpoint should be documented with:
19//! - 1) HTTP method e.g. `GET`
20//! - 2) Endpoint e.g. `/v1/file`
21//! - 3) Data used to make the request e.g. `VfsFileId`
22//! - 4) The return type e.g. `MaybeVfsFile`
23//!
24//! The methods below should resemble the data actually sent across the wire.
25//!
26//! [`Empty`]: crate::types::Empty
27//! [`UserPk`]: lexe_common::api::user::UserPk
28//! [`UserPkStruct`]: lexe_common::api::user::UserPkStruct
29
30#![deny(missing_docs)]
31// We don't export our traits currently so auto trait stability is not relevant.
32#![allow(async_fn_in_trait)]
33
34use std::collections::HashSet;
35
36use async_trait::async_trait;
37use bytes::Bytes;
38use lexe_common::api::{
39    MegaId,
40    auth::{
41        BearerAuthRequestWire, BearerAuthResponse, BearerAuthToken,
42        UserSignupRequestWire, UserSignupRequestWireV1,
43    },
44    fiat_rates::FiatRates,
45    models::{
46        SignMsgRequest, SignMsgResponse, Status, VerifyMsgRequest,
47        VerifyMsgResponse,
48    },
49    provision::NodeProvisionRequest,
50    revocable_clients::{
51        CreateRevocableClientRequest, CreateRevocableClientResponse,
52        GetRevocableClients, RevocableClients, UpdateClientRequest,
53        UpdateClientResponse,
54    },
55    test_event::TestEventOp,
56    user::{GetNewScidsRequest, MaybeScid, MaybeUser, Scids, UserPk},
57    version::{CurrentEnclaves, EnclavesToProvision, NodeEnclave},
58};
59#[cfg(doc)]
60use lexe_common::{
61    api::MegaIdStruct,
62    api::models::BroadcastedTxInfo,
63    api::user::NodePkStruct,
64    api::user::{UserPkSet, UserPkStruct},
65    api::version::MeasurementStruct,
66};
67use lexe_crypto::ed25519;
68use lexe_enclave::enclave::Measurement;
69use lightning::events::Event;
70
71#[cfg(doc)]
72use crate::types::payments::{PaymentCreatedIndex, PaymentId};
73use crate::{
74    error::{
75        BackendApiError, GatewayApiError, LspApiError, MegaApiError,
76        NodeApiError, RunnerApiError,
77    },
78    models::{
79        command::{
80            BackupInfo, ClaimGeneratedHumanBitcoinAddress, CloseChannelRequest,
81            CreateInvoiceRequest, CreateInvoiceResponse, CreateOfferRequest,
82            CreateOfferResponse, EnclavesToProvisionRequest,
83            GetAddressResponse, GetGeneratedUsernameResponse, GetNewPayments,
84            GetUpdatedPaymentMetadata, GetUpdatedPayments, HumanBitcoinAddress,
85            ListChannelsResponse, NodeInfo, OpenChannelRequest,
86            OpenChannelResponse, PayInvoiceRequest, PayInvoiceResponse,
87            PayOfferRequest, PayOfferResponse, PayOnchainRequest,
88            PayOnchainResponse, PaymentCreatedIndexStruct,
89            PaymentCreatedIndexes, PaymentIdStruct,
90            PreflightCloseChannelRequest, PreflightCloseChannelResponse,
91            PreflightOpenChannelRequest, PreflightOpenChannelResponse,
92            PreflightPayInvoiceRequest, PreflightPayInvoiceResponse,
93            PreflightPayOfferRequest, PreflightPayOfferResponse,
94            PreflightPayOnchainRequest, PreflightPayOnchainResponse,
95            ResyncRequest, SetupGDrive, UpdateHumanBitcoinAddress,
96            UpdatePaymentNote, VecPaymentId,
97        },
98        nwc::{
99            CreateNwcClientRequest, CreateNwcClientResponse, DbNwcClient,
100            DbNwcClientFields, GetNwcClients, ListNwcClientResponse,
101            NostrPkStruct, NostrSignedEvent, NwcRequest,
102            UpdateNwcClientRequest, UpdateNwcClientResponse, VecDbNwcClient,
103        },
104        runner::{
105            MegaNodeApiUserEvictRequest, MegaNodeApiUserRunRequest,
106            MegaNodeApiUserRunResponse, UserFinishedRequest,
107            UserLeaseRenewalRequest,
108        },
109    },
110    types::{
111        Empty,
112        lnurl::{
113            LnurlCallbackRequest, LnurlCallbackResponse, LnurlError,
114            LnurlPayRequestWire,
115        },
116        payments::{
117            DbPaymentMetadata, DbPaymentV1, DbPaymentV2, MaybeBasicPaymentV2,
118            MaybeDbPaymentMetadata, MaybeDbPaymentV1, MaybeDbPaymentV2,
119            VecBasicPaymentV1, VecBasicPaymentV2, VecDbPaymentMetadata,
120            VecDbPaymentV1, VecDbPaymentV2,
121        },
122        ports::MegaPorts,
123        sealed_seed::{MaybeSealedSeed, SealedSeed, SealedSeedId},
124        username::UsernameStruct,
125    },
126    vfs::{
127        MaybeVfsFile, VecVfsFile, VfsDirectory, VfsDirectoryList, VfsFile,
128        VfsFileId,
129    },
130};
131
132// TODO(max): To make clear that only upgradeable structs are being serialized,
133// these methods should take e.g. `&UserPkStruct` instead of `UserPk`.
134
135/// Defines the api that the backend exposes to the app (via the gateway).
136pub trait AppBackendApi {
137    /// POST /app/v2/signup [`ed25519::Signed<UserSignupRequestWire>`] ->
138    /// [`Empty`]
139    async fn signup_v2(
140        &self,
141        signed_req: &ed25519::Signed<&UserSignupRequestWire>,
142    ) -> Result<Empty, BackendApiError>;
143
144    /// POST /app/v1/signup [`ed25519::Signed<UserSignupRequestWireV1>`] ->
145    /// [`Empty`]
146    // TODO(phlip9): remove once all installed mobile clients above `app-v0.7.6`
147    #[deprecated = "Use the `signup_v2` API instead"]
148    async fn signup_v1(
149        &self,
150        signed_req: &ed25519::Signed<&UserSignupRequestWireV1>,
151    ) -> Result<Empty, BackendApiError>;
152
153    /// Query which node enclaves the user needs to provision to.
154    ///
155    /// POST /app/v1/enclaves_to_provision
156    /// [`EnclavesToProvisionRequest`] -> [`EnclavesToProvision`]
157    async fn enclaves_to_provision(
158        &self,
159        req: &EnclavesToProvisionRequest,
160        auth: BearerAuthToken,
161    ) -> Result<EnclavesToProvision, BackendApiError>;
162}
163
164/// Defines the api that the gateway directly exposes to the app.
165pub trait AppGatewayApi {
166    /// GET /app/v1/fiat_rates [`Empty`] -> [`FiatRates`]
167    async fn get_fiat_rates(&self) -> Result<FiatRates, GatewayApiError>;
168
169    /// Get the measurement and semver version of the latest node release.
170    ///
171    /// GET /app/v1/latest_release [`Empty`] -> [`NodeEnclave`]
172    #[deprecated(note = "since app-v0.8.1: Use current_releases() instead")]
173    async fn latest_release(&self) -> Result<NodeEnclave, GatewayApiError>;
174
175    /// Get the measurements, enclave machine id and versions of all
176    /// current node enclaves.
177    ///
178    /// GET /app/v1/current_releases [`Empty`] -> [`CurrentEnclaves`]
179    #[deprecated(note = "since app-v0.8.8: Use current_enclaves() instead")]
180    async fn current_releases(
181        &self,
182    ) -> Result<CurrentEnclaves, GatewayApiError>;
183
184    /// Get the measurements, enclave machine id and versions of all
185    /// current node enclaves.
186    ///
187    /// GET /app/v1/current_enclaves [`Empty`] -> [`CurrentEnclaves`]
188    async fn current_enclaves(
189        &self,
190    ) -> Result<CurrentEnclaves, GatewayApiError>;
191}
192
193/// Defines the api that the node exposes to the app during provisioning.
194pub trait AppNodeProvisionApi {
195    /// Provision a node with the given [`Measurement`]. The provisioning node's
196    /// remote attestation will be checked against the given [`Measurement`].
197    ///
198    /// POST /app/provision [`NodeProvisionRequest`] -> [`Empty`]
199    async fn provision(
200        &self,
201        measurement: Measurement,
202        data: NodeProvisionRequest,
203    ) -> Result<Empty, NodeApiError>;
204}
205
206/// Defines the api that the node exposes to the app during normal operation.
207pub trait AppNodeRunApi {
208    /// GET /app/node_info [`Empty`] -> [`NodeInfo`]
209    async fn node_info(&self) -> Result<NodeInfo, NodeApiError>;
210
211    /// GET /app/list_channels [`Empty`] -> [`ListChannelsResponse`]
212    async fn list_channels(&self)
213    -> Result<ListChannelsResponse, NodeApiError>;
214
215    /// POST /app/sign_message [`SignMsgRequest`] -> [`SignMsgResponse`]
216    ///
217    /// Introduced in `node-v0.6.5`.
218    async fn sign_message(
219        &self,
220        req: SignMsgRequest,
221    ) -> Result<SignMsgResponse, NodeApiError>;
222
223    /// POST /app/verify_message [`VerifyMsgRequest`] -> [`VerifyMsgResponse`]
224    ///
225    /// Introduced in `node-v0.6.5`.
226    async fn verify_message(
227        &self,
228        req: VerifyMsgRequest,
229    ) -> Result<VerifyMsgResponse, NodeApiError>;
230
231    /// POST /app/open_channel [`OpenChannelRequest`] -> [`OpenChannelResponse`]
232    ///
233    /// Opens a channel to the LSP.
234    async fn open_channel(
235        &self,
236        req: OpenChannelRequest,
237    ) -> Result<OpenChannelResponse, NodeApiError>;
238
239    /// POST /app/preflight_open_channel [`PreflightOpenChannelRequest`]
240    ///                                  -> [`PreflightOpenChannelResponse`]
241    ///
242    /// Estimate on-chain fees required for an [`open_channel`] to the LSP.
243    ///
244    /// [`open_channel`]: AppNodeRunApi::open_channel
245    async fn preflight_open_channel(
246        &self,
247        req: PreflightOpenChannelRequest,
248    ) -> Result<PreflightOpenChannelResponse, NodeApiError>;
249
250    /// POST /app/close_channel [`CloseChannelRequest`] -> [`Empty`]
251    ///
252    /// Closes a channel to the LSP.
253    async fn close_channel(
254        &self,
255        req: CloseChannelRequest,
256    ) -> Result<Empty, NodeApiError>;
257
258    /// POST /app/preflight_close_channel [`PreflightCloseChannelRequest`]
259    ///                                   -> [`PreflightCloseChannelResponse`]
260    ///
261    /// Estimate the on-chain fees required for a [`close_channel`].
262    ///
263    /// [`close_channel`]: AppNodeRunApi::close_channel
264    async fn preflight_close_channel(
265        &self,
266        req: PreflightCloseChannelRequest,
267    ) -> Result<PreflightCloseChannelResponse, NodeApiError>;
268
269    /// POST /app/create_invoice [`CreateInvoiceRequest`]
270    ///                          -> [`CreateInvoiceResponse`]
271    async fn create_invoice(
272        &self,
273        req: CreateInvoiceRequest,
274    ) -> Result<CreateInvoiceResponse, NodeApiError>;
275
276    /// POST /app/pay_invoice [`PayInvoiceRequest`] -> [`PayInvoiceResponse`]
277    async fn pay_invoice(
278        &self,
279        req: PayInvoiceRequest,
280    ) -> Result<PayInvoiceResponse, NodeApiError>;
281
282    /// POST /app/preflight_pay_invoice [`PreflightPayInvoiceRequest`]
283    ///                                 -> [`PreflightPayInvoiceResponse`]
284    ///
285    /// This endpoint lets the app ask its node to "pre-flight" a BOLT11 invoice
286    /// payment without going through with the actual payment. We verify as much
287    /// as we can, find a route, and get the fee estimates.
288    async fn preflight_pay_invoice(
289        &self,
290        req: PreflightPayInvoiceRequest,
291    ) -> Result<PreflightPayInvoiceResponse, NodeApiError>;
292
293    /// POST /app/create_offer [`CreateOfferRequest`] -> [`CreateOfferResponse`]
294    ///
295    /// Create a new Lightning offer (BOLT12).
296    //
297    // Added in `node-v0.7.3`.
298    async fn create_offer(
299        &self,
300        req: CreateOfferRequest,
301    ) -> Result<CreateOfferResponse, NodeApiError>;
302
303    /// POST /app/pay_offer [`PayOfferRequest`] -> [`PayOfferResponse`]
304    ///
305    /// Pay a Lightning offer (BOLT12).
306    //
307    // Added in `node-v0.7.4`.
308    async fn pay_offer(
309        &self,
310        req: PayOfferRequest,
311    ) -> Result<PayOfferResponse, NodeApiError>;
312
313    /// POST /app/preflight_pay_offer [`PreflightPayOfferRequest`]
314    ///                               -> [`PreflightPayOfferResponse`]
315    ///
316    /// This endpoint lets the app ask its node to "pre-flight" a Lightning
317    /// offer (BOLT12) payment without going through with the actual payment. We
318    /// verify as much as we can, find a route, and get the fee estimates.
319    //
320    // Added in `node-v0.7.4`.
321    async fn preflight_pay_offer(
322        &self,
323        req: PreflightPayOfferRequest,
324    ) -> Result<PreflightPayOfferResponse, NodeApiError>;
325
326    // TODO(phlip9): BOLT12: /app/request_refund
327
328    /// POST /app/get_address [`Empty`] -> [`GetAddressResponse`]
329    ///
330    /// Returns an address which can be used to receive funds. It is unused
331    /// unless there is an incoming tx and BDK hasn't detected it yet.
332    async fn get_address(&self) -> Result<GetAddressResponse, NodeApiError>;
333
334    /// POST /app/pay_onchain [`PayOnchainRequest`] -> [`PayOnchainResponse`]
335    ///
336    /// Pay bitcoin onchain. If the address is valid and we have sufficient
337    /// onchain funds, this will broadcast a new transaction to the bitcoin
338    /// mempool.
339    async fn pay_onchain(
340        &self,
341        req: PayOnchainRequest,
342    ) -> Result<PayOnchainResponse, NodeApiError>;
343
344    /// POST /app/preflight_pay_onchain [`PreflightPayOnchainRequest`]
345    ///                              -> [`PreflightPayOnchainResponse`]
346    ///
347    /// Returns estimated network fees for a potential onchain payment.
348    async fn preflight_pay_onchain(
349        &self,
350        req: PreflightPayOnchainRequest,
351    ) -> Result<PreflightPayOnchainResponse, NodeApiError>;
352
353    /// GET /app/v1/payments/id [`PaymentIdStruct`] -> [`MaybeBasicPaymentV2`]
354    //
355    // Added in `node-v0.8.10`.
356    async fn get_payment_by_id(
357        &self,
358        req: PaymentIdStruct,
359    ) -> Result<MaybeBasicPaymentV2, NodeApiError>;
360
361    /// POST /app/payments/indexes [`PaymentCreatedIndexes`]
362    ///                         -> [`VecDbPaymentV1`]
363    ///
364    /// Fetch a batch of payments by their [`PaymentCreatedIndex`]s. This is
365    /// typically used by a mobile client to poll for updates on payments
366    /// which it currently has stored locally as "pending"; the intention is
367    /// to check if any of these payments have been updated.
368    //
369    // We use POST because there may be a lot of idxs, which might be too large
370    // to fit inside query parameters.
371    #[deprecated(note = "since app-v0.8.9+29 and sdk-sidecar-v0.3.1: \
372                         Use get_payments_by_ids instead")]
373    async fn get_payments_by_indexes(
374        &self,
375        req: PaymentCreatedIndexes,
376    ) -> Result<VecBasicPaymentV1, NodeApiError>;
377
378    /// GET /app/payments/new [`GetNewPayments`] -> [`VecBasicPaymentV1`]
379    #[deprecated(note = "since app-v0.8.9+29 and sdk-sidecar-v0.3.1: \
380                         Use get_updated_payments instead")]
381    async fn get_new_payments(
382        &self,
383        req: GetNewPayments,
384    ) -> Result<VecBasicPaymentV1, NodeApiError>;
385
386    /// GET /app/payments/updated [`GetUpdatedPayments`]
387    ///                        -> [`VecBasicPaymentV2`]
388    async fn get_updated_payments(
389        &self,
390        req: GetUpdatedPayments,
391    ) -> Result<VecBasicPaymentV2, NodeApiError>;
392
393    /// PUT /app/payments/note [`UpdatePaymentNote`] -> [`Empty`]
394    async fn update_payment_note(
395        &self,
396        req: UpdatePaymentNote,
397    ) -> Result<Empty, NodeApiError>;
398
399    /// Lists all revocable clients.
400    ///
401    /// GET /app/clients [`GetRevocableClients`] -> [`RevocableClients`]
402    // Added in `node-0.7.9`
403    async fn get_revocable_clients(
404        &self,
405        req: GetRevocableClients,
406    ) -> Result<RevocableClients, NodeApiError>;
407
408    /// Creates a new revocable client. Returns the newly issued client cert.
409    ///
410    /// POST /app/clients [`CreateRevocableClientRequest`]
411    ///                   -> [`CreateRevocableClientResponse`]
412    // Added in `node-0.7.9`
413    async fn create_revocable_client(
414        &self,
415        req: CreateRevocableClientRequest,
416    ) -> Result<CreateRevocableClientResponse, NodeApiError>;
417
418    /// Updates this revocable client. Returns the updated client.
419    ///
420    /// PUT /app/clients [`UpdateClientRequest`] -> [`UpdateClientResponse`]
421    // Added in `node-0.7.9`
422    async fn update_revocable_client(
423        &self,
424        req: UpdateClientRequest,
425    ) -> Result<UpdateClientResponse, NodeApiError>;
426
427    /// List all broadcasted transactions.
428    ///
429    /// GET /app/list_broadcasted_txs [`Empty`] -> [`Vec<BroadcastedTxInfo>`]
430    async fn list_broadcasted_txs(
431        &self,
432    ) -> Result<serde_json::Value, NodeApiError>;
433
434    /// Get the current status of Node backup.
435    ///
436    /// GET /app/backup [`Empty`] -> [`BackupInfo`]
437    async fn backup_info(&self) -> Result<BackupInfo, NodeApiError>;
438
439    /// Setup GDrive backup.
440    ///
441    /// POST /app/backup/gdrive [`SetupGDrive`] -> [`Empty`]
442    async fn setup_gdrive(
443        &self,
444        req: SetupGDrive,
445    ) -> Result<Empty, NodeApiError>;
446
447    /// Get current user's human Bitcoin address.
448    ///
449    /// GET /app/human_bitcoin_address [`Empty`] -> [`HumanBitcoinAddress`]
450    async fn get_human_bitcoin_address(
451        &self,
452    ) -> Result<HumanBitcoinAddress, NodeApiError>;
453
454    /// Update current user's human Bitcoin address.
455    ///
456    /// PUT /app/human_bitcoin_address [`UsernameStruct`] ->
457    /// [`HumanBitcoinAddress`]
458    async fn update_human_bitcoin_address(
459        &self,
460        req: UsernameStruct,
461    ) -> Result<HumanBitcoinAddress, NodeApiError>;
462
463    /// GET /app/payment_address [`Empty`] -> [`HumanBitcoinAddress`]
464    #[deprecated(note = "since app-v0.9.3 and sdk-sidecar-v0.4.2: \
465                         Use get_human_bitcoin_address instead")]
466    async fn get_payment_address(
467        &self,
468    ) -> Result<HumanBitcoinAddress, NodeApiError> {
469        self.get_human_bitcoin_address().await
470    }
471
472    /// PUT /app/payment_address [`UsernameStruct`] -> [`HumanBitcoinAddress`]
473    #[deprecated(note = "since app-v0.9.3 and sdk-sidecar-v0.4.2: \
474                         Use update_human_bitcoin_address instead")]
475    async fn update_payment_address(
476        &self,
477        req: UsernameStruct,
478    ) -> Result<HumanBitcoinAddress, NodeApiError> {
479        self.update_human_bitcoin_address(req).await
480    }
481
482    /// List NWC clients for the current user.
483    /// Returns client info without sensitive data (no connection strings).
484    ///
485    /// GET /app/nwc_clients [`Empty`] -> [`ListNwcClientResponse`]
486    async fn list_nwc_clients(
487        &self,
488    ) -> Result<ListNwcClientResponse, NodeApiError>;
489
490    /// Create a new NWC client.
491    /// Generates new keys and returns the connection string.
492    ///
493    /// POST /app/nwc_clients [`CreateNwcClientRequest`]
494    ///                    -> [`CreateNwcClientResponse`]
495    async fn create_nwc_client(
496        &self,
497        req: CreateNwcClientRequest,
498    ) -> Result<CreateNwcClientResponse, NodeApiError>;
499
500    /// Update an existing NWC client's label.
501    ///
502    /// PUT /app/nwc_clients [`UpdateNwcClientRequest`]
503    ///                   -> [`UpdateNwcClientResponse`]
504    async fn update_nwc_client(
505        &self,
506        req: UpdateNwcClientRequest,
507    ) -> Result<UpdateNwcClientResponse, NodeApiError>;
508
509    /// Delete an NWC client given its nostr client public key.
510    ///
511    /// DELETE /app/nwc_clients [`NostrPkStruct`] -> [`Empty`]
512    async fn delete_nwc_client(
513        &self,
514        req: NostrPkStruct,
515    ) -> Result<Empty, NodeApiError>;
516}
517
518/// The bearer auth API exposed by the backend (sometimes via the gateway) to
519/// various consumers. This trait is defined separately from the
520/// usual `ConsumerServiceApi` traits because `BearerAuthenticator` needs to
521/// abstract over a generic implementor of [`BearerAuthBackendApi`].
522#[async_trait]
523pub trait BearerAuthBackendApi {
524    /// POST /CONSUMER/bearer_auth [`ed25519::Signed<BearerAuthRequest>`]
525    ///                         -> [`BearerAuthResponse`]
526    ///
527    /// Valid values for `CONSUMER` are: "app", "node" and "lsp".
528    async fn bearer_auth(
529        &self,
530        signed_req: &ed25519::Signed<&BearerAuthRequestWire>,
531    ) -> Result<BearerAuthResponse, BackendApiError>;
532}
533
534/// Defines the API the mega node exposes to the Lexe operators.
535///
536/// NOTE: For performance, this API does not use TLS! This API should only
537/// contain methods for limited operational and lifecycle management endpoints.
538pub trait LexeMegaApi {
539    /// POST /lexe/run_user [`MegaNodeApiUserRunRequest`]
540    ///                  -> [`MegaNodeApiUserRunResponse`]
541    async fn run_user(
542        &self,
543        req: MegaNodeApiUserRunRequest,
544    ) -> Result<MegaNodeApiUserRunResponse, MegaApiError>;
545
546    /// POST /lexe/evict_user [`MegaNodeApiUserEvictRequest`] -> [`Empty`]
547    async fn evict_user(
548        &self,
549        req: MegaNodeApiUserEvictRequest,
550    ) -> Result<Empty, MegaApiError>;
551
552    /// GET /lexe/status [`MegaIdStruct`] -> [`Status`]
553    async fn status_mega(
554        &self,
555        mega_id: MegaId,
556    ) -> Result<Status, MegaApiError>;
557
558    /// POST /lexe/shutdown [`Empty`] -> [`Empty`]
559    async fn shutdown_mega(&self) -> Result<Empty, MegaApiError>;
560}
561
562/// Defines the API the node exposes to the Lexe operators at run time.
563///
564/// NOTE: For performance, this API does not use TLS! This API should only
565/// contain methods for limited operational and lifecycle management endpoints.
566pub trait LexeNodeRunApi {
567    /// GET /lexe/status [`UserPkStruct`] -> [`Status`]
568    async fn status_run(&self, user_pk: UserPk)
569    -> Result<Status, NodeApiError>;
570
571    /// POST /lexe/resync [`ResyncRequest`] -> [`Empty`]
572    ///
573    /// Triggers an immediate resync of BDK and LDK. Optionally full sync the
574    /// BDK wallet. Returns only once sync has either completed or timed out.
575    async fn resync(&self, req: ResyncRequest) -> Result<Empty, NodeApiError>;
576
577    /// POST /lexe/test_event [`TestEventOp`] -> [`Empty`]
578    ///
579    /// Calls the corresponding `TestEventReceiver` method.
580    /// This endpoint can only be called by one caller at any one time.
581    /// Does nothing and returns an error if called in prod.
582    async fn test_event(&self, op: &TestEventOp)
583    -> Result<Empty, NodeApiError>;
584
585    /// GET /lexe/shutdown [`UserPkStruct`] -> [`Empty`]
586    ///
587    /// Not to be confused with [`LexeMegaApi::shutdown_mega`].
588    async fn shutdown_run(
589        &self,
590        user_pk: UserPk,
591    ) -> Result<Empty, NodeApiError>;
592
593    /// POST /lexe/create_invoice [`CreateInvoiceRequest`] ->
594    /// [`CreateInvoiceResponse`]
595    async fn create_invoice(
596        &self,
597        req: CreateInvoiceRequest,
598    ) -> Result<CreateInvoiceResponse, NodeApiError>;
599
600    /// POST /lexe/nwc_request [`NwcRequest`] -> [`NostrSignedEvent`]
601    ///
602    /// Processes an encrypted NWC request from the nostr-bridge.
603    /// The node will decrypt the request, execute the command, and return
604    /// an encrypted response.
605    async fn nwc_request(
606        &self,
607        req: NwcRequest,
608    ) -> Result<NostrSignedEvent, NodeApiError>;
609}
610
611/// Defines the API the runner exposes to mega nodes.
612pub trait MegaRunnerApi {
613    /// POST /mega/ready [`MegaPorts`] -> [`Empty`]
614    ///
615    /// Indicates this mega node is initialized and ready to load user nodes.
616    async fn mega_ready(
617        &self,
618        ports: &MegaPorts,
619    ) -> Result<Empty, RunnerApiError>;
620
621    /// POST /mega/activity [`UserPkSet`] -> [`Empty`]
622    ///
623    /// Indicates the meganode received some activity from its users.
624    async fn activity(
625        &self,
626        user_pks: HashSet<UserPk>,
627    ) -> Result<Empty, RunnerApiError>;
628
629    /// POST /mega/user_finished [`UserFinishedRequest`] -> [`Empty`]
630    ///
631    /// Notifies the runner that a user has shut down,
632    /// and that the user's lease can be terminated.
633    async fn user_finished(
634        &self,
635        req: &UserFinishedRequest,
636    ) -> Result<Empty, RunnerApiError>;
637}
638
639/// Defines the api that the backend exposes to the node.
640pub trait NodeBackendApi {
641    // --- Unauthenticated --- //
642
643    /// GET /node/v1/user [`UserPkStruct`] -> [`MaybeUser`]
644    async fn get_user(
645        &self,
646        user_pk: UserPk,
647    ) -> Result<MaybeUser, BackendApiError>;
648
649    /// GET /node/v1/sealed_seed [`SealedSeedId`] -> [`MaybeSealedSeed`]
650    async fn get_sealed_seed(
651        &self,
652        data: &SealedSeedId,
653    ) -> Result<MaybeSealedSeed, BackendApiError>;
654
655    // --- Bearer authentication required --- //
656
657    /// PUT /node/v1/sealed_seed [`SealedSeed`] -> [`Empty`]
658    ///
659    /// Idempotent: does nothing if the [`SealedSeedId`] already exists.
660    async fn create_sealed_seed(
661        &self,
662        data: &SealedSeed,
663        auth: BearerAuthToken,
664    ) -> Result<Empty, BackendApiError>;
665
666    /// Delete all sealed seeds which have the given measurement and the user_pk
667    /// of the authenticated user.
668    ///
669    /// DELETE /node/v1/sealed_seed [`MeasurementStruct`] -> [`Empty`]
670    async fn delete_sealed_seeds(
671        &self,
672        measurement: Measurement,
673        auth: BearerAuthToken,
674    ) -> Result<Empty, BackendApiError>;
675
676    /// GET /node/v1/scids [`Empty`] -> [`Scids`]
677    async fn get_scids(
678        &self,
679        auth: BearerAuthToken,
680    ) -> Result<Scids, BackendApiError>;
681
682    /// GET /node/v1/scid [`Empty`] -> [`MaybeScid`]
683    // NOTE: Keep this def around until we can remove the backend handler.
684    #[deprecated(note = "since lsp-v0.7.3: Use multi scid version instead")]
685    async fn get_scid(
686        &self,
687        auth: BearerAuthToken,
688    ) -> Result<MaybeScid, BackendApiError>;
689
690    /// GET /node/v1/file [`VfsFileId`] -> [`MaybeVfsFile`]
691    #[deprecated(note = "since node-v0.8.5: Use get_file instead")]
692    async fn get_file_v1(
693        &self,
694        file_id: &VfsFileId,
695        auth: BearerAuthToken,
696    ) -> Result<MaybeVfsFile, BackendApiError>;
697
698    /// GET /node/v2/file [`VfsFileId`] -> [`Bytes`] ([`VfsFile::data`])
699    async fn get_file(
700        &self,
701        file_id: &VfsFileId,
702        token: BearerAuthToken,
703    ) -> Result<Bytes, BackendApiError>;
704
705    /// POST /node/v1/file [`VfsFile`] -> [`Empty`]
706    #[deprecated(note = "since node-v0.8.5: Use create_file instead")]
707    async fn create_file_v1(
708        &self,
709        file: &VfsFile,
710        auth: BearerAuthToken,
711    ) -> Result<Empty, BackendApiError>;
712
713    /// POST /node/v2/file [`VfsFileId`] (query) + [`Bytes`] (body) -> [`Empty`]
714    async fn create_file(
715        &self,
716        file_id: &VfsFileId,
717        data: bytes::Bytes,
718        auth: BearerAuthToken,
719    ) -> Result<Empty, BackendApiError>;
720
721    /// PUT /node/v1/file [`VfsFile`] -> [`Empty`]
722    #[deprecated(note = "since node-v0.8.5: Use upsert_file instead")]
723    async fn upsert_file_v1(
724        &self,
725        file: &VfsFile,
726        auth: BearerAuthToken,
727    ) -> Result<Empty, BackendApiError>;
728
729    /// PUT /node/v2/file [`VfsFileId`] (query) + [`Bytes`] (body) -> [`Empty`]
730    async fn upsert_file(
731        &self,
732        file_id: &VfsFileId,
733        data: bytes::Bytes,
734        auth: BearerAuthToken,
735    ) -> Result<Empty, BackendApiError>;
736
737    /// DELETE /node/v1/file [`VfsFileId`] -> [`Empty`]
738    ///
739    /// Returns [`Ok`] only if exactly one row was deleted.
740    async fn delete_file(
741        &self,
742        file_id: &VfsFileId,
743        auth: BearerAuthToken,
744    ) -> Result<Empty, BackendApiError>;
745
746    /// GET /node/v1/directory [`VfsDirectory`] -> [`VecVfsFile`]
747    #[deprecated(note = "since node-v0.8.5: Use list_directory instead")]
748    async fn get_directory_v1(
749        &self,
750        dir: &VfsDirectory,
751        auth: BearerAuthToken,
752    ) -> Result<VecVfsFile, BackendApiError>;
753
754    /// GET /node/v2/directory [`VfsDirectory`] -> [`VecVfsFile`]
755    async fn list_directory(
756        &self,
757        dir: &VfsDirectory,
758        auth: BearerAuthToken,
759    ) -> Result<VfsDirectoryList, BackendApiError>;
760
761    /// GET /node/v1/payments [`PaymentCreatedIndexStruct`]
762    ///                    -> [`MaybeDbPaymentV1`]
763    #[deprecated(note = "since node-v0.8.8: Use get_payment_by_index instead")]
764    async fn get_payment_by_index_v1(
765        &self,
766        req: PaymentCreatedIndexStruct,
767        auth: BearerAuthToken,
768    ) -> Result<MaybeDbPaymentV1, BackendApiError>;
769
770    /// POST /node/v1/payments [`DbPaymentV1`] -> [`Empty`]
771    #[deprecated(note = "since node-v0.8.10: Use upsert_payment instead")]
772    async fn create_payment(
773        &self,
774        payment: DbPaymentV1,
775        auth: BearerAuthToken,
776    ) -> Result<Empty, BackendApiError>;
777
778    /// PUT /node/v1/payments [`DbPaymentV1`] -> [`Empty`]
779    #[deprecated(note = "since node-v0.8.8: Use upsert_payment instead")]
780    async fn upsert_payment_v1(
781        &self,
782        payment: DbPaymentV1,
783        auth: BearerAuthToken,
784    ) -> Result<Empty, BackendApiError>;
785
786    /// PUT /node/v2/payments [`DbPaymentV2`] -> [`Empty`]
787    async fn upsert_payment(
788        &self,
789        payment: DbPaymentV2,
790        auth: BearerAuthToken,
791    ) -> Result<Empty, BackendApiError>;
792
793    /// GET /node/v1/payments/id [`PaymentIdStruct`] -> [`MaybeDbPaymentV1`]
794    #[deprecated(note = "since node-v0.8.10: Use get_payment_by_id instead")]
795    async fn get_payment_by_id_v1(
796        &self,
797        req: PaymentIdStruct,
798        auth: BearerAuthToken,
799    ) -> Result<MaybeDbPaymentV1, BackendApiError>;
800
801    /// GET /node/v2/payments/id [`PaymentIdStruct`] -> [`MaybeDbPaymentV2`]
802    async fn get_payment_by_id(
803        &self,
804        req: PaymentIdStruct,
805        auth: BearerAuthToken,
806    ) -> Result<MaybeDbPaymentV2, BackendApiError>;
807
808    /// GET /node/v1/payments/index [`PaymentCreatedIndexStruct`]
809    ///                          -> [`MaybeDbPaymentV1`]
810    #[deprecated(note = "since node-v0.8.10: Use get_payment_by_id instead")]
811    async fn get_payment_by_index(
812        &self,
813        req: PaymentCreatedIndexStruct,
814        auth: BearerAuthToken,
815    ) -> Result<MaybeDbPaymentV1, BackendApiError>;
816
817    /// PUT /node/v1/payments/batch [`VecDbPaymentV1`] -> [`Empty`]
818    ///
819    /// ACID endpoint for upserting a batch of payments.
820    #[deprecated(note = "since node-v0.8.8: Use upsert_payment_batch instead")]
821    async fn upsert_payment_batch_v1(
822        &self,
823        payments: VecDbPaymentV1,
824        auth: BearerAuthToken,
825    ) -> Result<Empty, BackendApiError>;
826
827    /// PUT /node/v2/payments/batch [`VecDbPaymentV2`] -> [`Empty`]
828    ///
829    /// ACID endpoint for upserting a batch of payments.
830    async fn upsert_payment_batch(
831        &self,
832        payments: VecDbPaymentV2,
833        auth: BearerAuthToken,
834    ) -> Result<Empty, BackendApiError>;
835
836    /// POST /node/v1/payments/indexes [`PaymentCreatedIndexes`]
837    ///                             -> [`VecDbPaymentV1`]
838    ///
839    /// Fetch a batch of payments by their [`PaymentCreatedIndex`]s. This is
840    /// typically used by a mobile client to poll for updates on payments
841    /// which it currently has stored locally as "pending"; the intention is
842    /// to check if any of these payments have been updated.
843    //
844    // We use POST because there may be a lot of idxs, which might be too large
845    // to fit inside query parameters.
846    #[deprecated(note = "since node-v0.8.10: Use get_payments_by_ids instead")]
847    async fn get_payments_by_indexes(
848        &self,
849        req: PaymentCreatedIndexes,
850        auth: BearerAuthToken,
851    ) -> Result<VecDbPaymentV1, BackendApiError>;
852
853    /// POST /node/v1/payments/ids [`VecPaymentId`]
854    ///                         -> [`VecDbPaymentV2`]
855    ///
856    /// Fetch a batch of payments by their [`PaymentId`]s.
857    //
858    // We use POST because there may be a lot of ids,
859    // which might be too large to fit inside query params.
860    async fn get_payments_by_ids(
861        &self,
862        req: VecPaymentId,
863        auth: BearerAuthToken,
864    ) -> Result<VecDbPaymentV2, BackendApiError>;
865
866    /// GET /node/v1/payments/new [`GetNewPayments`] -> [`VecDbPaymentV1`]
867    ///
868    /// Sync a batch of new payments to local storage, optionally starting from
869    /// a known [`PaymentCreatedIndex`] (exclusive).
870    /// Results are in ascending order, by `(created_at, payment_id)`.
871    /// See [`GetNewPayments`] for more info.
872    #[deprecated(note = "since app-v0.8.9+29 and sdk-sidecar-v0.3.1: \
873                         Use get_updated_payments instead")]
874    // NOTE: This fn is used in the app->node handler for /app/payments/new, so
875    // the node->backend client code must remain until all app and sdk-sidecar
876    // clients have been updated.
877    async fn get_new_payments(
878        &self,
879        req: GetNewPayments,
880        auth: BearerAuthToken,
881    ) -> Result<VecDbPaymentV1, BackendApiError>;
882
883    /// GET /node/v1/payments/updated [`GetUpdatedPayments`]
884    ///                            -> [`VecDbPaymentV2`]
885    async fn get_updated_payments(
886        &self,
887        req: GetUpdatedPayments,
888        auth: BearerAuthToken,
889    ) -> Result<VecDbPaymentV2, BackendApiError>;
890
891    /// GET /node/v1/payments/pending -> [`VecDbPaymentV1`]
892    ///
893    /// Fetches all pending payments.
894    #[deprecated(note = "since node-v0.8.10: Use get_pending_payments instead")]
895    async fn get_pending_payments_v1(
896        &self,
897        auth: BearerAuthToken,
898    ) -> Result<VecDbPaymentV1, BackendApiError>;
899
900    /// GET /node/v2/payments/pending -> [`VecDbPaymentV2`]
901    ///
902    /// Fetches all pending payments.
903    async fn get_pending_payments(
904        &self,
905        auth: BearerAuthToken,
906    ) -> Result<VecDbPaymentV2, BackendApiError>;
907
908    /// GET /node/v1/payments/final -> [`VecPaymentId`]
909    ///
910    /// Fetches the IDs of all finalized payments.
911    #[deprecated(note = "since node-v0.8.8")]
912    async fn get_finalized_payment_ids(
913        &self,
914        auth: BearerAuthToken,
915    ) -> Result<VecPaymentId, BackendApiError>;
916
917    /// PUT /node/v1/payments/metadata [`DbPaymentMetadata`] -> [`Empty`]
918    async fn upsert_payment_metadata(
919        &self,
920        metadata: DbPaymentMetadata,
921        auth: BearerAuthToken,
922    ) -> Result<Empty, BackendApiError>;
923
924    /// PUT /node/v1/payments/metadata/batch [`VecDbPaymentMetadata`]
925    ///                                   -> [`Empty`]
926    ///
927    /// ACID endpoint for upserting a batch of payments metadata.
928    async fn upsert_payment_metadata_batch(
929        &self,
930        payments: VecDbPaymentMetadata,
931        auth: BearerAuthToken,
932    ) -> Result<Empty, BackendApiError>;
933
934    /// GET /node/v1/payments/metadata/id [`PaymentIdStruct`]
935    ///                                -> [`MaybeDbPaymentMetadata`]
936    ///
937    /// Fetch a payment metadata by its [`PaymentId`].
938    async fn get_payment_metadata_by_id(
939        &self,
940        req: PaymentIdStruct,
941        token: BearerAuthToken,
942    ) -> Result<MaybeDbPaymentMetadata, BackendApiError>;
943
944    /// POST /node/v1/payments/metadata/ids [`VecPaymentId`]
945    ///                                  -> [`VecDbPaymentMetadata`]
946    ///
947    /// Fetch a batch of payment metadata by their [`PaymentId`]s.
948    //
949    // We use POST because there may be a lot of ids,
950    // which might be too large to fit inside query params.
951    async fn get_payment_metadata_by_ids(
952        &self,
953        req: VecPaymentId,
954        token: BearerAuthToken,
955    ) -> Result<VecDbPaymentMetadata, BackendApiError>;
956
957    /// GET /node/v1/payments/metadata/updated [`GetUpdatedPaymentMetadata`]
958    ///                                     -> [`VecDbPaymentMetadata`]
959    ///
960    /// Get a batch of payment metadata in asc `(updated_at, payment_id)` order.
961    async fn get_updated_payment_metadata(
962        &self,
963        req: GetUpdatedPaymentMetadata,
964        auth: BearerAuthToken,
965    ) -> Result<VecDbPaymentMetadata, BackendApiError>;
966
967    /// PUT /node/v1/human_bitcoin_address [`UpdateHumanBitcoinAddress`]
968    ///                         -> [`HumanBitcoinAddress`]
969    ///
970    /// Updates the human Bitcoin address (username and offer) of the given
971    /// node.
972    async fn update_human_bitcoin_address(
973        &self,
974        req: UpdateHumanBitcoinAddress,
975        auth: BearerAuthToken,
976    ) -> Result<HumanBitcoinAddress, BackendApiError>;
977
978    /// PUT /node/v1/payment_address [`UpdateHumanBitcoinAddress`]
979    ///                           -> [`HumanBitcoinAddress`]
980    #[deprecated(note = "since node-v0.9.3: \
981                         Use update_human_bitcoin_address instead")]
982    async fn update_payment_address(
983        &self,
984        req: UpdateHumanBitcoinAddress,
985        auth: BearerAuthToken,
986    ) -> Result<HumanBitcoinAddress, BackendApiError> {
987        self.update_human_bitcoin_address(req, auth).await
988    }
989
990    /// GET /node/v1/human_bitcoin_address [`Empty`] -> [`HumanBitcoinAddress`]
991    ///
992    /// Fetches the node's primary human Bitcoin address (username and offer).
993    async fn get_human_bitcoin_address(
994        &self,
995        auth: BearerAuthToken,
996    ) -> Result<HumanBitcoinAddress, BackendApiError>;
997
998    /// GET /node/v1/payment_address [`Empty`] -> [`HumanBitcoinAddress`]
999    #[deprecated(note = "since node-v0.9.3: \
1000                         Use get_human_bitcoin_address instead")]
1001    async fn get_payment_address(
1002        &self,
1003        auth: BearerAuthToken,
1004    ) -> Result<HumanBitcoinAddress, BackendApiError> {
1005        self.get_human_bitcoin_address(auth).await
1006    }
1007
1008    /// POST /node/v1/claim_generated_human_bitcoin_address
1009    ///   [`ClaimGeneratedHumanBitcoinAddress`] -> [`Empty`]
1010    ///
1011    /// Claims a generated human Bitcoin address for the given node.
1012    async fn claim_generated_human_bitcoin_address(
1013        &self,
1014        req: ClaimGeneratedHumanBitcoinAddress,
1015        auth: BearerAuthToken,
1016    ) -> Result<Empty, BackendApiError>;
1017
1018    /// POST /node/v1/claim_generated_payment_address
1019    ///   [`ClaimGeneratedHumanBitcoinAddress`] -> [`Empty`]
1020    #[deprecated(note = "since node-v0.9.3: \
1021                         Use claim_generated_human_bitcoin_address instead")]
1022    async fn claim_generated_payment_address(
1023        &self,
1024        req: ClaimGeneratedHumanBitcoinAddress,
1025        auth: BearerAuthToken,
1026    ) -> Result<Empty, BackendApiError> {
1027        self.claim_generated_human_bitcoin_address(req, auth).await
1028    }
1029
1030    /// GET /node/v1/generated_username [`Empty`]
1031    ///                              -> [`GetGeneratedUsernameResponse`]
1032    ///
1033    /// Generates an available username for the authenticated user without
1034    /// storing it. The username is derived deterministically from the
1035    /// user's `user_pk`, with collision handling via numeric suffixes.
1036    async fn get_generated_username(
1037        &self,
1038        auth: BearerAuthToken,
1039    ) -> Result<GetGeneratedUsernameResponse, BackendApiError>;
1040
1041    /// GET /node/v1/nwc_clients [`Empty`] -> [`VecDbNwcClient`]
1042    ///
1043    /// Fetches the node's NWC clients and optionally filters by
1044    /// client_nostr_pk.
1045    async fn get_nwc_clients(
1046        &self,
1047        req: GetNwcClients,
1048        auth: BearerAuthToken,
1049    ) -> Result<VecDbNwcClient, BackendApiError>;
1050
1051    /// PUT /node/v1/nwc_clients [`DbNwcClientFields`] -> [`DbNwcClient`]
1052    ///
1053    /// Upserts a NWC client in the database.
1054    async fn upsert_nwc_client(
1055        &self,
1056        req: DbNwcClientFields,
1057        auth: BearerAuthToken,
1058    ) -> Result<DbNwcClient, BackendApiError>;
1059
1060    /// DELETE /node/v1/nwc_clients [`NostrPkStruct`] -> [`Empty`]
1061    ///
1062    /// Deletes a NWC client given its nostr client public key.
1063    async fn delete_nwc_client(
1064        &self,
1065        req: NostrPkStruct,
1066        auth: BearerAuthToken,
1067    ) -> Result<Empty, BackendApiError>;
1068}
1069
1070/// Defines the api that the LSP exposes to user nodes.
1071pub trait NodeLspApi {
1072    /// GET /node/v1/scids [`GetNewScidsRequest`] -> [`Scids`]
1073    async fn get_new_scids(
1074        &self,
1075        req: &GetNewScidsRequest,
1076    ) -> Result<Scids, LspApiError>;
1077
1078    /// GET /node/v1/network_graph [`Empty`] -> [`Bytes`] (LDK-serialized graph)
1079    ///
1080    /// Introduced in node-v0.6.8 and lsp-v0.6.29.
1081    async fn get_network_graph(&self) -> Result<Bytes, LspApiError>;
1082
1083    /// GET /node/v1/prob_scorer [`Empty`]
1084    ///                       -> [`Bytes`] (LDK-serialized probabilistic scorer)
1085    ///
1086    /// Introduced in node-v0.6.17 and lsp-v0.6.33.
1087    async fn get_prob_scorer(&self) -> Result<Bytes, LspApiError>;
1088
1089    /// POST /node/v1/payment_path [`Bytes`] (LDK-serialized [`Event`])
1090    ///                         -> [`Empty`]
1091    ///
1092    /// Sends an anonymized successful or failed payment path to the LSP to
1093    /// update Lexe's shared network graph and improve payment reliability.
1094    ///
1095    /// Introduced in node-v0.6.17 and lsp-v0.6.33.
1096    async fn payment_path(&self, event: &Event) -> Result<Empty, LspApiError>;
1097}
1098
1099/// Defines the api that the runner exposes to the user node.
1100pub trait NodeRunnerApi {
1101    /// POST /node/renew_lease [`UserLeaseRenewalRequest`] -> [`Empty`]
1102    ///
1103    /// Renew's a user node's lease with the megarunner.
1104    async fn renew_lease(
1105        &self,
1106        req: &UserLeaseRenewalRequest,
1107    ) -> Result<Empty, RunnerApiError>;
1108
1109    /// POST /node/sync_success [`UserPkStruct`] -> [`Empty`]
1110    ///
1111    /// Indicates the node successfully completed sync.
1112    async fn sync_succ(&self, user_pk: UserPk)
1113    -> Result<Empty, RunnerApiError>;
1114}
1115
1116/// Defines the api that the gateway exposes to the internet.
1117pub trait PublicGatewayApi {
1118    /// Get the LNURL pay request message, if any username has been set.
1119    /// Uses lnurl_callback endpoint as the callback.
1120    ///
1121    /// GET /.well-known/lnurlp/{username}
1122    async fn get_lnurl_pay_request(
1123        &self,
1124    ) -> Result<LnurlPayRequestWire, LnurlError>;
1125
1126    /// Resolves the invoice given a LNURL pay request previously generated.
1127    /// Ciphertext is a base64 encoded string of the username and
1128    /// other metadata information.
1129    ///
1130    /// GET /public/v1/lnurl_callback/{encoded_params}
1131    async fn lnurl_callback(
1132        &self,
1133        req: LnurlCallbackRequest,
1134    ) -> Result<LnurlCallbackResponse, LnurlError>;
1135}