Skip to main content

breez_sdk_spark/common/
models.rs

1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
5#[macros::derive_from(breez_sdk_common::network::BitcoinNetwork)]
6#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
7pub enum BitcoinNetwork {
8    /// Mainnet
9    Bitcoin,
10    Testnet3,
11    Testnet4,
12    Signet,
13    Regtest,
14}
15
16#[derive(Clone, Debug, Error)]
17#[macros::derive_from(breez_sdk_common::input::ParseError)]
18pub enum ParseError {
19    #[error("empty input")]
20    EmptyInput,
21    #[error("Bip-21 error: {0}")]
22    Bip21Error(Bip21Error),
23    #[error("invalid input")]
24    InvalidInput,
25    #[error("Lnurl error: {0}")]
26    LnurlError(LnurlError),
27    #[error("Service connectivity error: {0}")]
28    ServiceConnectivity(ServiceConnectivityError),
29    #[error("Invalid external input parser: {0}")]
30    InvalidExternalInputParser(String),
31}
32
33#[derive(Clone, Debug, Error)]
34#[macros::derive_from(breez_sdk_common::input::Bip21Error)]
35pub enum Bip21Error {
36    #[error("bip21 contains invalid address")]
37    InvalidAddress,
38    #[error("bip21 contains invalid amount")]
39    InvalidAmount,
40    #[error("bip21 contains invalid parameter value for '{0}'")]
41    InvalidParameter(String),
42    #[error("bip21 parameter missing equals character")]
43    MissingEquals,
44    #[error("bip21 contains parameter '{0}' multiple times")]
45    MultipleParams(String),
46    #[error("bip21 contains unknown required parameter '{0}'")]
47    UnknownRequiredParameter(String),
48    #[error("bip21 does not contain any payment methods")]
49    NoPaymentMethods,
50}
51
52#[derive(Clone, Debug, Error)]
53#[macros::derive_from(breez_sdk_common::lnurl::error::LnurlError)]
54pub enum LnurlError {
55    #[error("lnurl missing k1 parameter")]
56    MissingK1,
57    #[error("lnurl contains invalid k1 parameter")]
58    InvalidK1,
59    #[error("lnurl contains unsupported action")]
60    UnsupportedAction,
61    #[error("lnurl missing domain")]
62    MissingDomain,
63    #[error("error calling lnurl endpoint: {0}")]
64    ServiceConnectivity(#[from] ServiceConnectivityError),
65    #[error("endpoint error: {0}")]
66    EndpointError(String),
67    #[error("lnurl has http scheme without onion domain")]
68    HttpSchemeWithoutOnionDomain,
69    #[error("lnurl has https scheme with onion domain")]
70    HttpsSchemeWithOnionDomain,
71    #[error("lnurl error: {0}")]
72    General(String),
73    #[error("lnurl has unknown scheme")]
74    UnknownScheme,
75    #[error("lnurl has invalid uri: {0}")]
76    InvalidUri(String),
77    #[error("lnurl has invalid invoice: {0}")]
78    InvalidInvoice(String),
79    #[error("lnurl has invalid response: {0}")]
80    InvalidResponse(String),
81}
82
83#[derive(Clone, Debug, Error)]
84#[macros::derive_from(breez_sdk_common::error::ServiceConnectivityError)]
85#[macros::derive_into(breez_sdk_common::error::ServiceConnectivityError)]
86#[cfg_attr(feature = "uniffi", derive(uniffi::Error))]
87pub enum ServiceConnectivityError {
88    #[error("Builder error: {0}")]
89    Builder(String),
90    #[error("Redirect error: {0}")]
91    Redirect(String),
92    #[error("Status error: {status} - {body}")]
93    Status { status: u16, body: String },
94    #[error("Timeout error: {0}")]
95    Timeout(String),
96    #[error("Request error: {0}")]
97    Request(String),
98    #[error("Connect error: {0}")]
99    Connect(String),
100    #[error("Body error: {0}")]
101    Body(String),
102    #[error("Decode error: {0}")]
103    Decode(String),
104    #[error("Json error: {0}")]
105    Json(String),
106    #[error("Other error: {0}")]
107    Other(String),
108}
109
110#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
111#[macros::derive_from(breez_sdk_common::input::Amount)]
112#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
113pub enum Amount {
114    Bitcoin {
115        amount_msat: u64,
116    },
117    /// An amount of currency specified using ISO 4712.
118    Currency {
119        /// The currency that the amount is denominated in.
120        iso4217_code: String,
121        /// The amount in the currency unit adjusted by the ISO 4712 exponent (e.g., USD cents).
122        fractional_amount: u64,
123    },
124}
125
126#[derive(Clone, Debug, Default, Deserialize, Serialize)]
127#[macros::derive_from(breez_sdk_common::input::Bip21Details)]
128#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
129pub struct Bip21Details {
130    pub amount_sat: Option<u64>,
131    pub asset_id: Option<String>,
132    pub uri: String,
133    pub extras: Vec<Bip21Extra>,
134    pub label: Option<String>,
135    pub message: Option<String>,
136    pub payment_methods: Vec<InputType>,
137}
138
139#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
140#[macros::derive_from(breez_sdk_common::input::Bip21Extra)]
141#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
142pub struct Bip21Extra {
143    pub key: String,
144    pub value: String,
145}
146
147#[derive(Clone, Debug, Deserialize, Serialize)]
148#[macros::derive_from(breez_sdk_common::input::BitcoinAddressDetails)]
149#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
150pub struct BitcoinAddressDetails {
151    pub address: String,
152    pub network: BitcoinNetwork,
153    pub source: PaymentRequestSource,
154}
155
156#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
157#[macros::derive_from(breez_sdk_common::input::Bolt11Invoice)]
158#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
159pub struct Bolt11Invoice {
160    pub bolt11: String,
161    pub source: PaymentRequestSource,
162}
163
164#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
165#[macros::derive_from(breez_sdk_common::input::Bolt11RouteHint)]
166#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
167pub struct Bolt11RouteHint {
168    pub hops: Vec<Bolt11RouteHintHop>,
169}
170
171#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
172#[macros::derive_from(breez_sdk_common::input::Bolt11RouteHintHop)]
173#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
174pub struct Bolt11RouteHintHop {
175    /// The `node_id` of the non-target end of the route
176    pub src_node_id: String,
177    /// The `short_channel_id` of this channel
178    pub short_channel_id: String,
179    /// The fees which must be paid to use this channel
180    pub fees_base_msat: u32,
181    pub fees_proportional_millionths: u32,
182
183    /// The difference in CLTV values between this node and the next node.
184    pub cltv_expiry_delta: u16,
185    /// The minimum value, in msat, which must be relayed to the next hop.
186    pub htlc_minimum_msat: Option<u64>,
187    /// The maximum value in msat available for routing with a single HTLC.
188    pub htlc_maximum_msat: Option<u64>,
189}
190
191#[derive(Clone, Debug, Deserialize, Serialize)]
192#[macros::derive_from(breez_sdk_common::input::Bolt12Invoice)]
193#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
194pub struct Bolt12Invoice {
195    pub invoice: String,
196    pub source: PaymentRequestSource,
197}
198
199#[derive(Clone, Debug, Deserialize, Serialize)]
200#[macros::derive_from(breez_sdk_common::input::Bolt12InvoiceRequestDetails)]
201#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
202pub struct Bolt12InvoiceRequestDetails {
203    // TODO: Fill fields
204}
205
206#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
207#[macros::derive_from(breez_sdk_common::input::Bolt12OfferBlindedPath)]
208#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
209pub struct Bolt12OfferBlindedPath {
210    pub blinded_hops: Vec<String>,
211}
212
213#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
214#[macros::derive_from(breez_sdk_common::input::Bolt11InvoiceDetails)]
215#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
216pub struct Bolt11InvoiceDetails {
217    pub amount_msat: Option<u64>,
218    pub description: Option<String>,
219    pub description_hash: Option<String>,
220    pub expiry: u64,
221    pub invoice: Bolt11Invoice,
222    pub min_final_cltv_expiry_delta: u64,
223    pub network: BitcoinNetwork,
224    pub payee_pubkey: String,
225    pub payment_hash: String,
226    pub payment_secret: String,
227    pub routing_hints: Vec<Bolt11RouteHint>,
228    pub timestamp: u64,
229}
230
231#[derive(Clone, Debug, Deserialize, Serialize)]
232#[macros::derive_from(breez_sdk_common::input::Bolt12InvoiceDetails)]
233#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
234pub struct Bolt12InvoiceDetails {
235    pub amount_msat: u64,
236    pub invoice: Bolt12Invoice,
237}
238
239#[derive(Clone, Debug, Deserialize, Serialize)]
240#[macros::derive_from(breez_sdk_common::input::Bolt12Offer)]
241#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
242pub struct Bolt12Offer {
243    pub offer: String,
244    pub source: PaymentRequestSource,
245}
246
247#[derive(Clone, Debug, Deserialize, Serialize)]
248#[macros::derive_from(breez_sdk_common::input::Bolt12OfferDetails)]
249#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
250pub struct Bolt12OfferDetails {
251    pub absolute_expiry: Option<u64>,
252    pub chains: Vec<String>,
253    pub description: Option<String>,
254    pub issuer: Option<String>,
255    pub min_amount: Option<Amount>,
256    pub offer: Bolt12Offer,
257    pub paths: Vec<Bolt12OfferBlindedPath>,
258    pub signing_pubkey: Option<String>,
259}
260
261#[derive(Clone, Debug, Deserialize, Serialize)]
262#[macros::derive_from(breez_sdk_common::input::InputType)]
263#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
264pub enum InputType {
265    BitcoinAddress(BitcoinAddressDetails),
266    Bolt11Invoice(Bolt11InvoiceDetails),
267    Bolt12Invoice(Bolt12InvoiceDetails),
268    Bolt12Offer(Bolt12OfferDetails),
269    LightningAddress(LightningAddressDetails),
270    LnurlPay(LnurlPayRequestDetails),
271    SilentPaymentAddress(SilentPaymentAddressDetails),
272    LnurlAuth(LnurlAuthRequestDetails),
273    Url(String),
274    Bip21(Bip21Details),
275    Bolt12InvoiceRequest(Bolt12InvoiceRequestDetails),
276    LnurlWithdraw(LnurlWithdrawRequestDetails),
277    SparkAddress(SparkAddressDetails),
278    SparkInvoice(SparkInvoiceDetails),
279    CrossChainAddress(CrossChainAddressDetails),
280}
281
282#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
283#[macros::derive_from(breez_sdk_common::input::CrossChainAddressFamily)]
284#[macros::derive_into(breez_sdk_common::input::CrossChainAddressFamily)]
285#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
286#[serde(rename_all = "snake_case")]
287pub enum CrossChainAddressFamily {
288    Evm,
289    Solana,
290    Tron,
291}
292
293#[derive(Clone, Debug, Deserialize, Serialize)]
294#[macros::derive_from(breez_sdk_common::input::CrossChainAddressDetails)]
295#[macros::derive_into(breez_sdk_common::input::CrossChainAddressDetails)]
296#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
297pub struct CrossChainAddressDetails {
298    pub address: String,
299    pub address_family: CrossChainAddressFamily,
300    pub contract_address: Option<String>,
301    pub chain_id: Option<u64>,
302    pub amount: Option<u128>,
303}
304
305#[derive(Clone, Debug, Deserialize, Serialize)]
306#[macros::derive_from(breez_sdk_common::lnurl::pay::LnurlPayRequestDetails)]
307#[macros::derive_into(breez_sdk_common::lnurl::pay::LnurlPayRequestDetails)]
308#[serde(rename_all = "camelCase")]
309#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
310pub struct LnurlPayRequestDetails {
311    pub callback: String,
312    /// The minimum amount, in millisats, that this LNURL-pay endpoint accepts
313    pub min_sendable: u64,
314    /// The maximum amount, in millisats, that this LNURL-pay endpoint accepts
315    pub max_sendable: u64,
316    /// As per LUD-06, `metadata` is a raw string (e.g. a json representation of the inner map).
317    /// Use `metadata_vec()` to get the parsed items.
318    #[serde(rename(deserialize = "metadata"))]
319    pub metadata_str: String,
320    /// The comment length accepted by this endpoint
321    ///
322    /// See <https://github.com/lnurl/luds/blob/luds/12.md>
323    #[serde(default)]
324    pub comment_allowed: u16,
325
326    /// Indicates the domain of the LNURL-pay service, to be shown to the user when asking for
327    /// payment input, as per LUD-06 spec.
328    ///
329    /// Note: this is not the domain of the callback, but the domain of the LNURL-pay endpoint.
330    #[serde(skip)]
331    pub domain: String,
332
333    #[serde(skip)]
334    pub url: String,
335
336    /// Optional lightning address if that was used to resolve the lnurl.
337    #[serde(skip)]
338    pub address: Option<String>,
339
340    /// Value indicating whether the recipient supports Nostr Zaps through NIP-57.
341    ///
342    /// See <https://github.com/nostr-protocol/nips/blob/master/57.md>
343    pub allows_nostr: Option<bool>,
344    /// Optional recipient's lnurl provider's Nostr pubkey for NIP-57. If it exists it should be a
345    /// valid BIP 340 public key in hex.
346    ///
347    /// See <https://github.com/nostr-protocol/nips/blob/master/57.md>
348    /// See <https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki>
349    pub nostr_pubkey: Option<String>,
350}
351
352/// Wrapped in a [`InputType::LnurlAuth`], this is the result of parsing a LNURL-auth endpoint.
353///
354/// It represents the endpoint's parameters for the LNURL workflow.
355///
356/// See <https://github.com/lnurl/luds/blob/luds/04.md>
357#[derive(Clone, Debug, Deserialize, Serialize)]
358#[macros::derive_from(breez_sdk_common::lnurl::auth::LnurlAuthRequestDetails)]
359#[macros::derive_into(breez_sdk_common::lnurl::auth::LnurlAuthRequestDetails)]
360#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
361pub struct LnurlAuthRequestDetails {
362    /// Hex encoded 32 bytes of challenge
363    pub k1: String,
364
365    /// When available, one of: register, login, link, auth
366    pub action: Option<String>,
367
368    /// Indicates the domain of the LNURL-auth service, to be shown to the user when asking for
369    /// auth confirmation, as per LUD-04 spec.
370    #[serde(skip_serializing, skip_deserializing)]
371    pub domain: String,
372
373    /// Indicates the URL of the LNURL-auth service, including the query arguments. This will be
374    /// extended with the signed challenge and the linking key, then called in the second step of the workflow.
375    #[serde(skip_serializing, skip_deserializing)]
376    pub url: String,
377}
378
379/// LNURL error details
380#[derive(Clone, Debug, Deserialize, Serialize)]
381#[macros::derive_from(breez_sdk_common::lnurl::LnurlErrorDetails)]
382#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
383pub struct LnurlErrorDetails {
384    pub reason: String,
385}
386
387/// The response from a LNURL-auth callback, indicating success or failure.
388#[derive(Clone, Debug, Deserialize, Serialize)]
389#[macros::derive_from(breez_sdk_common::lnurl::LnurlCallbackStatus)]
390#[serde(rename_all = "UPPERCASE")]
391#[serde(tag = "status")]
392#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
393pub enum LnurlCallbackStatus {
394    /// On-wire format is: `{"status": "OK"}`
395    Ok,
396    /// On-wire format is: `{"status": "ERROR", "reason": "error details..."}`
397    #[serde(rename = "ERROR")]
398    ErrorStatus {
399        #[serde(flatten)]
400        error_details: LnurlErrorDetails,
401    },
402}
403
404#[derive(Clone, Debug, Deserialize, Serialize)]
405#[macros::derive_from(breez_sdk_common::lnurl::withdraw::LnurlWithdrawRequestDetails)]
406#[macros::derive_into(breez_sdk_common::lnurl::withdraw::LnurlWithdrawRequestDetails)]
407#[serde(rename_all = "camelCase")]
408#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
409pub struct LnurlWithdrawRequestDetails {
410    pub callback: String,
411    pub k1: String,
412    pub default_description: String,
413    /// The minimum amount, in millisats, that this LNURL-withdraw endpoint accepts
414    pub min_withdrawable: u64,
415    /// The maximum amount, in millisats, that this LNURL-withdraw endpoint accepts
416    pub max_withdrawable: u64,
417    /// The URL of the LNURL-withdraw endpoint these details were fetched from.
418    /// Set when the details come from parsing an input; determines how far the
419    /// withdraw flow trusts the endpoint-chosen `callback`. Absent or empty
420    /// means no exemption: the callback is held to the public-host rules.
421    #[serde(default)]
422    #[cfg_attr(feature = "uniffi", uniffi(default = ""))]
423    pub url: String,
424}
425
426#[derive(Clone, Debug, Deserialize, Serialize)]
427#[macros::derive_from(breez_sdk_common::input::SparkAddressDetails)]
428#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
429pub struct SparkAddressDetails {
430    /// The raw address string
431    pub address: String,
432    /// The identity public key of the address owner
433    pub identity_public_key: String,
434    pub network: BitcoinNetwork,
435    pub source: PaymentRequestSource,
436}
437
438#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
439#[macros::derive_from(breez_sdk_common::input::SparkInvoiceDetails)]
440#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
441pub struct SparkInvoiceDetails {
442    /// The raw invoice string
443    pub invoice: String,
444    /// The identity public key of the invoice issuer
445    pub identity_public_key: String,
446    pub network: BitcoinNetwork,
447    /// Optional amount denominated in sats if `token_identifier` is absent, otherwise in the token base units
448    pub amount: Option<u128>,
449    /// The token identifier of the token payment. Absence indicates a Bitcoin payment.
450    pub token_identifier: Option<String>,
451    /// Optional expiry time as a unix timestamp in seconds. If not provided, the invoice will never expire.
452    pub expiry_time: Option<u64>,
453    /// Optional description.
454    pub description: Option<String>,
455    /// If set, the invoice may only be fulfilled by a payer with this public key.
456    pub sender_public_key: Option<String>,
457}
458
459#[derive(Clone, Debug, Deserialize, Serialize)]
460#[macros::derive_from(breez_sdk_common::input::LightningAddressDetails)]
461#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
462pub struct LightningAddressDetails {
463    pub address: String,
464    pub pay_request: LnurlPayRequestDetails,
465}
466
467#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
468#[macros::derive_from(breez_sdk_common::input::PaymentRequestSource)]
469#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
470pub struct PaymentRequestSource {
471    pub bip_21_uri: Option<String>,
472    pub bip_353_address: Option<String>,
473}
474
475#[derive(Clone, Debug, Deserialize, Serialize)]
476#[macros::derive_from(breez_sdk_common::input::SilentPaymentAddressDetails)]
477#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
478pub struct SilentPaymentAddressDetails {
479    pub address: String,
480    pub network: BitcoinNetwork,
481    pub source: PaymentRequestSource,
482}
483
484/// Configuration for an external input parser
485#[derive(Debug, Clone, Serialize)]
486#[macros::derive_from(breez_sdk_common::input::ExternalInputParser)]
487#[macros::derive_into(breez_sdk_common::input::ExternalInputParser)]
488#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
489pub struct ExternalInputParser {
490    /// An arbitrary parser provider id
491    pub provider_id: String,
492    /// The external parser will be used when an input conforms to this regex
493    pub input_regex: String,
494    /// The URL of the parser containing a placeholder `<input>` that will be replaced with the
495    /// input to be parsed. The input is sanitized using percent encoding.
496    pub parser_url: String,
497}
498
499/// Supported success action types
500///
501/// Receiving any other (unsupported) success action type will result in a failed parsing,
502/// which will abort the LNURL-pay workflow, as per LUD-09.
503#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
504#[macros::derive_from(breez_sdk_common::lnurl::pay::SuccessAction)]
505#[macros::derive_into(breez_sdk_common::lnurl::pay::SuccessAction)]
506#[serde(rename_all = "camelCase")]
507#[serde(tag = "tag")]
508#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
509pub enum SuccessAction {
510    /// AES type, described in LUD-10
511    Aes {
512        #[serde(flatten)]
513        data: AesSuccessActionData,
514    },
515
516    /// Message type, described in LUD-09
517    Message {
518        #[serde(flatten)]
519        data: MessageSuccessActionData,
520    },
521
522    /// URL type, described in LUD-09
523    Url {
524        #[serde(flatten)]
525        data: UrlSuccessActionData,
526    },
527}
528
529/// [`SuccessAction`] where contents are ready to be consumed by the caller
530///
531/// Contents are identical to [`SuccessAction`], except for AES where the ciphertext is decrypted.
532#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
533#[macros::derive_from(breez_sdk_common::lnurl::pay::SuccessActionProcessed)]
534#[macros::derive_into(breez_sdk_common::lnurl::pay::SuccessActionProcessed)]
535#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
536pub enum SuccessActionProcessed {
537    /// See [`SuccessAction::Aes`] for received payload
538    ///
539    /// See [`AesSuccessActionDataDecrypted`] for decrypted payload
540    Aes { result: AesSuccessActionDataResult },
541
542    /// See [`SuccessAction::Message`]
543    Message { data: MessageSuccessActionData },
544
545    /// See [`SuccessAction::Url`]
546    Url { data: UrlSuccessActionData },
547}
548
549/// Payload of the AES success action, as received from the LNURL endpoint
550///
551/// See [`AesSuccessActionDataDecrypted`] for a similar wrapper containing the decrypted payload
552#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
553#[macros::derive_from(breez_sdk_common::lnurl::pay::AesSuccessActionData)]
554#[macros::derive_into(breez_sdk_common::lnurl::pay::AesSuccessActionData)]
555#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
556pub struct AesSuccessActionData {
557    /// Contents description, up to 144 characters
558    pub description: String,
559
560    /// Base64, AES-encrypted data where encryption key is payment preimage, up to 4kb of characters
561    pub ciphertext: String,
562
563    /// Base64, initialization vector, exactly 24 characters
564    pub iv: String,
565}
566
567/// Result of decryption of [`AesSuccessActionData`] payload
568#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
569#[macros::derive_from(breez_sdk_common::lnurl::pay::AesSuccessActionDataResult)]
570#[macros::derive_into(breez_sdk_common::lnurl::pay::AesSuccessActionDataResult)]
571#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
572pub enum AesSuccessActionDataResult {
573    Decrypted { data: AesSuccessActionDataDecrypted },
574    ErrorStatus { reason: String },
575}
576
577/// Wrapper for the decrypted [`AesSuccessActionData`] payload
578#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
579#[macros::derive_from(breez_sdk_common::lnurl::pay::AesSuccessActionDataDecrypted)]
580#[macros::derive_into(breez_sdk_common::lnurl::pay::AesSuccessActionDataDecrypted)]
581#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
582pub struct AesSuccessActionDataDecrypted {
583    /// Contents description, up to 144 characters
584    pub description: String,
585
586    /// Decrypted content
587    pub plaintext: String,
588}
589
590#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
591#[macros::derive_from(breez_sdk_common::lnurl::pay::MessageSuccessActionData)]
592#[macros::derive_into(breez_sdk_common::lnurl::pay::MessageSuccessActionData)]
593#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
594pub struct MessageSuccessActionData {
595    pub message: String,
596}
597
598#[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)]
599#[macros::derive_from(breez_sdk_common::lnurl::pay::UrlSuccessActionData)]
600#[macros::derive_into(breez_sdk_common::lnurl::pay::UrlSuccessActionData)]
601#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
602pub struct UrlSuccessActionData {
603    /// Contents description, up to 144 characters
604    pub description: String,
605
606    /// URL of the success action
607    pub url: String,
608
609    /// Indicates the success URL domain matches the LNURL callback domain.
610    ///
611    /// See <https://github.com/lnurl/luds/blob/luds/09.md>
612    pub matches_callback_domain: bool,
613}
614
615#[cfg(test)]
616mod tests {
617    use super::LnurlWithdrawRequestDetails;
618
619    /// Withdraw details stored by older SDK versions carry no `url`; they must
620    /// keep deserializing, with the empty url falling back to strict callback
621    /// rules.
622    #[test]
623    fn withdraw_details_deserialize_without_url() {
624        let details: LnurlWithdrawRequestDetails = serde_json::from_str(
625            r#"{
626                "callback": "https://service.com/cb",
627                "k1": "abc",
628                "defaultDescription": "d",
629                "minWithdrawable": 1000,
630                "maxWithdrawable": 2000
631            }"#,
632        )
633        .unwrap();
634        assert_eq!(details.url, "");
635    }
636}