mirror of
https://github.com/aljazceru/breez-sdk-liquid.git
synced 2026-01-31 20:04:29 +01:00
Rework draining to enable BOLT12 drain
(cherry picked from commit dba144f2e483e21d821dc7a19d379ca9ceaad12d)
This commit is contained in:
@@ -405,24 +405,9 @@ pub(crate) async fn handle_command(
|
||||
drain,
|
||||
delay,
|
||||
} => {
|
||||
let destination = match (invoice, offer, address) {
|
||||
(Some(invoice), None, None) => Ok(invoice),
|
||||
(None, Some(offer), None) => match amount_sat {
|
||||
Some(_) => Ok(offer),
|
||||
None => Err(anyhow!(
|
||||
"Must specify an amount for a BOLT12 offer."
|
||||
))
|
||||
},
|
||||
(None, None, Some(address)) => Ok(address),
|
||||
(Some(_), _, Some(_)) => {
|
||||
Err(anyhow::anyhow!(
|
||||
"Cannot specify both invoice and address at the same time."
|
||||
))
|
||||
}
|
||||
_ => Err(anyhow!(
|
||||
"Must specify either a BOLT11 invoice, a BOLT12 offer or a direct/BIP21 address."
|
||||
))
|
||||
}?;
|
||||
let destination = invoice.or(offer.or(address)).ok_or(anyhow!(
|
||||
"Must specify either a BOLT11 invoice, a BOLT12 offer or a direct/BIP21 address."
|
||||
))?;
|
||||
let amount = match (asset_id, amount, amount_sat, drain.unwrap_or(false)) {
|
||||
(Some(asset_id), Some(receiver_amount), _, _) => Some(PayAmount::Asset {
|
||||
asset_id,
|
||||
|
||||
@@ -285,6 +285,26 @@ typedef struct wire_cst_ln_url_pay_request_data {
|
||||
struct wire_cst_list_prim_u_8_strict *ln_address;
|
||||
} wire_cst_ln_url_pay_request_data;
|
||||
|
||||
typedef struct wire_cst_PayAmount_Bitcoin {
|
||||
uint64_t receiver_amount_sat;
|
||||
} wire_cst_PayAmount_Bitcoin;
|
||||
|
||||
typedef struct wire_cst_PayAmount_Asset {
|
||||
struct wire_cst_list_prim_u_8_strict *asset_id;
|
||||
double receiver_amount;
|
||||
bool *estimate_asset_fees;
|
||||
} wire_cst_PayAmount_Asset;
|
||||
|
||||
typedef union PayAmountKind {
|
||||
struct wire_cst_PayAmount_Bitcoin Bitcoin;
|
||||
struct wire_cst_PayAmount_Asset Asset;
|
||||
} PayAmountKind;
|
||||
|
||||
typedef struct wire_cst_pay_amount {
|
||||
int32_t tag;
|
||||
union PayAmountKind kind;
|
||||
} wire_cst_pay_amount;
|
||||
|
||||
typedef struct wire_cst_aes_success_action_data {
|
||||
struct wire_cst_list_prim_u_8_strict *description;
|
||||
struct wire_cst_list_prim_u_8_strict *ciphertext;
|
||||
@@ -328,6 +348,7 @@ typedef struct wire_cst_prepare_ln_url_pay_response {
|
||||
struct wire_cst_send_destination destination;
|
||||
uint64_t fees_sat;
|
||||
struct wire_cst_ln_url_pay_request_data data;
|
||||
struct wire_cst_pay_amount amount;
|
||||
struct wire_cst_list_prim_u_8_strict *comment;
|
||||
struct wire_cst_success_action *success_action;
|
||||
} wire_cst_prepare_ln_url_pay_response;
|
||||
@@ -366,26 +387,6 @@ typedef struct wire_cst_prepare_buy_bitcoin_request {
|
||||
uint64_t amount_sat;
|
||||
} wire_cst_prepare_buy_bitcoin_request;
|
||||
|
||||
typedef struct wire_cst_PayAmount_Bitcoin {
|
||||
uint64_t receiver_amount_sat;
|
||||
} wire_cst_PayAmount_Bitcoin;
|
||||
|
||||
typedef struct wire_cst_PayAmount_Asset {
|
||||
struct wire_cst_list_prim_u_8_strict *asset_id;
|
||||
double receiver_amount;
|
||||
bool *estimate_asset_fees;
|
||||
} wire_cst_PayAmount_Asset;
|
||||
|
||||
typedef union PayAmountKind {
|
||||
struct wire_cst_PayAmount_Bitcoin Bitcoin;
|
||||
struct wire_cst_PayAmount_Asset Asset;
|
||||
} PayAmountKind;
|
||||
|
||||
typedef struct wire_cst_pay_amount {
|
||||
int32_t tag;
|
||||
union PayAmountKind kind;
|
||||
} wire_cst_pay_amount;
|
||||
|
||||
typedef struct wire_cst_prepare_ln_url_pay_request {
|
||||
struct wire_cst_ln_url_pay_request_data data;
|
||||
struct wire_cst_pay_amount amount;
|
||||
@@ -461,6 +462,7 @@ typedef struct wire_cst_restore_request {
|
||||
|
||||
typedef struct wire_cst_prepare_send_response {
|
||||
struct wire_cst_send_destination destination;
|
||||
struct wire_cst_pay_amount *amount;
|
||||
uint64_t *fees_sat;
|
||||
double *estimated_asset_fees;
|
||||
} wire_cst_prepare_send_response;
|
||||
|
||||
@@ -423,6 +423,7 @@ dictionary PrepareLnUrlPayResponse {
|
||||
SendDestination destination;
|
||||
u64 fees_sat;
|
||||
LnUrlPayRequestData data;
|
||||
PayAmount amount;
|
||||
string? comment = null;
|
||||
SuccessAction? success_action = null;
|
||||
};
|
||||
@@ -445,6 +446,7 @@ interface SendDestination {
|
||||
|
||||
dictionary PrepareSendResponse {
|
||||
SendDestination destination;
|
||||
PayAmount? amount;
|
||||
u64? fees_sat;
|
||||
f64? estimated_asset_fees;
|
||||
};
|
||||
|
||||
@@ -4297,6 +4297,7 @@ impl SseDecode for crate::model::PrepareLnUrlPayResponse {
|
||||
let mut var_destination = <crate::model::SendDestination>::sse_decode(deserializer);
|
||||
let mut var_feesSat = <u64>::sse_decode(deserializer);
|
||||
let mut var_data = <crate::bindings::LnUrlPayRequestData>::sse_decode(deserializer);
|
||||
let mut var_amount = <crate::model::PayAmount>::sse_decode(deserializer);
|
||||
let mut var_comment = <Option<String>>::sse_decode(deserializer);
|
||||
let mut var_successAction =
|
||||
<Option<crate::bindings::SuccessAction>>::sse_decode(deserializer);
|
||||
@@ -4304,6 +4305,7 @@ impl SseDecode for crate::model::PrepareLnUrlPayResponse {
|
||||
destination: var_destination,
|
||||
fees_sat: var_feesSat,
|
||||
data: var_data,
|
||||
amount: var_amount,
|
||||
comment: var_comment,
|
||||
success_action: var_successAction,
|
||||
};
|
||||
@@ -4412,10 +4414,12 @@ impl SseDecode for crate::model::PrepareSendResponse {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||
let mut var_destination = <crate::model::SendDestination>::sse_decode(deserializer);
|
||||
let mut var_amount = <Option<crate::model::PayAmount>>::sse_decode(deserializer);
|
||||
let mut var_feesSat = <Option<u64>>::sse_decode(deserializer);
|
||||
let mut var_estimatedAssetFees = <Option<f64>>::sse_decode(deserializer);
|
||||
return crate::model::PrepareSendResponse {
|
||||
destination: var_destination,
|
||||
amount: var_amount,
|
||||
fees_sat: var_feesSat,
|
||||
estimated_asset_fees: var_estimatedAssetFees,
|
||||
};
|
||||
@@ -6745,6 +6749,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PrepareLnUrlPayResponse {
|
||||
self.destination.into_into_dart().into_dart(),
|
||||
self.fees_sat.into_into_dart().into_dart(),
|
||||
self.data.into_into_dart().into_dart(),
|
||||
self.amount.into_into_dart().into_dart(),
|
||||
self.comment.into_into_dart().into_dart(),
|
||||
self.success_action.into_into_dart().into_dart(),
|
||||
]
|
||||
@@ -6921,6 +6926,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PrepareSendResponse {
|
||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||
[
|
||||
self.destination.into_into_dart().into_dart(),
|
||||
self.amount.into_into_dart().into_dart(),
|
||||
self.fees_sat.into_into_dart().into_dart(),
|
||||
self.estimated_asset_fees.into_into_dart().into_dart(),
|
||||
]
|
||||
@@ -9085,6 +9091,7 @@ impl SseEncode for crate::model::PrepareLnUrlPayResponse {
|
||||
<crate::model::SendDestination>::sse_encode(self.destination, serializer);
|
||||
<u64>::sse_encode(self.fees_sat, serializer);
|
||||
<crate::bindings::LnUrlPayRequestData>::sse_encode(self.data, serializer);
|
||||
<crate::model::PayAmount>::sse_encode(self.amount, serializer);
|
||||
<Option<String>>::sse_encode(self.comment, serializer);
|
||||
<Option<crate::bindings::SuccessAction>>::sse_encode(self.success_action, serializer);
|
||||
}
|
||||
@@ -9157,6 +9164,7 @@ impl SseEncode for crate::model::PrepareSendResponse {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||
<crate::model::SendDestination>::sse_encode(self.destination, serializer);
|
||||
<Option<crate::model::PayAmount>>::sse_encode(self.amount, serializer);
|
||||
<Option<u64>>::sse_encode(self.fees_sat, serializer);
|
||||
<Option<f64>>::sse_encode(self.estimated_asset_fees, serializer);
|
||||
}
|
||||
@@ -11324,6 +11332,7 @@ mod io {
|
||||
destination: self.destination.cst_decode(),
|
||||
fees_sat: self.fees_sat.cst_decode(),
|
||||
data: self.data.cst_decode(),
|
||||
amount: self.amount.cst_decode(),
|
||||
comment: self.comment.cst_decode(),
|
||||
success_action: self.success_action.cst_decode(),
|
||||
}
|
||||
@@ -11404,6 +11413,7 @@ mod io {
|
||||
fn cst_decode(self) -> crate::model::PrepareSendResponse {
|
||||
crate::model::PrepareSendResponse {
|
||||
destination: self.destination.cst_decode(),
|
||||
amount: self.amount.cst_decode(),
|
||||
fees_sat: self.fees_sat.cst_decode(),
|
||||
estimated_asset_fees: self.estimated_asset_fees.cst_decode(),
|
||||
}
|
||||
@@ -12696,6 +12706,7 @@ mod io {
|
||||
destination: Default::default(),
|
||||
fees_sat: Default::default(),
|
||||
data: Default::default(),
|
||||
amount: Default::default(),
|
||||
comment: core::ptr::null_mut(),
|
||||
success_action: core::ptr::null_mut(),
|
||||
}
|
||||
@@ -12808,6 +12819,7 @@ mod io {
|
||||
fn new_with_null_ptr() -> Self {
|
||||
Self {
|
||||
destination: Default::default(),
|
||||
amount: core::ptr::null_mut(),
|
||||
fees_sat: core::ptr::null_mut(),
|
||||
estimated_asset_fees: core::ptr::null_mut(),
|
||||
}
|
||||
@@ -15213,6 +15225,7 @@ mod io {
|
||||
destination: wire_cst_send_destination,
|
||||
fees_sat: u64,
|
||||
data: wire_cst_ln_url_pay_request_data,
|
||||
amount: wire_cst_pay_amount,
|
||||
comment: *mut wire_cst_list_prim_u_8_strict,
|
||||
success_action: *mut wire_cst_success_action,
|
||||
}
|
||||
@@ -15269,6 +15282,7 @@ mod io {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct wire_cst_prepare_send_response {
|
||||
destination: wire_cst_send_destination,
|
||||
amount: *mut wire_cst_pay_amount,
|
||||
fees_sat: *mut u64,
|
||||
estimated_asset_fees: *mut f64,
|
||||
}
|
||||
|
||||
@@ -729,6 +729,8 @@ pub enum SendDestination {
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct PrepareSendResponse {
|
||||
pub destination: SendDestination,
|
||||
/// The optional amount to be sent in either Bitcoin or another asset
|
||||
pub amount: Option<PayAmount>,
|
||||
/// The optional estimated fee in satoshi. Is set when there is Bitcoin available
|
||||
/// to pay fees. When not set, there are asset fees available to pay fees.
|
||||
pub fees_sat: Option<u64>,
|
||||
@@ -2296,6 +2298,8 @@ pub struct PrepareLnUrlPayResponse {
|
||||
pub fees_sat: u64,
|
||||
/// The [LnUrlPayRequestData] returned by [parse]
|
||||
pub data: LnUrlPayRequestData,
|
||||
/// The amount to send
|
||||
pub amount: PayAmount,
|
||||
/// An optional comment for this payment
|
||||
pub comment: Option<String>,
|
||||
/// The unprocessed LUD-09 success action. This will be processed and decrypted if
|
||||
|
||||
@@ -1219,6 +1219,7 @@ impl LiquidSdk {
|
||||
/// # Returns
|
||||
/// Returns a [PrepareSendResponse] containing:
|
||||
/// * `destination` - the parsed destination, of type [SendDestination]
|
||||
/// * `amount` - the optional [PayAmount] to be sent in either Bitcoin or another asset
|
||||
/// * `fees_sat` - the optional estimated fee in satoshi. Is set when there is Bitcoin
|
||||
/// available to pay fees. When not set, there are asset fees available to pay fees.
|
||||
/// * `estimated_asset_fees` - the optional estimated fee in the asset. Is set when
|
||||
@@ -1399,76 +1400,105 @@ impl LiquidSdk {
|
||||
.map(|(address, _)| address);
|
||||
asset_id = self.config.lbtc_asset_id();
|
||||
estimated_asset_fees = None;
|
||||
(receiver_amount_sat, fees_sat, payment_destination) =
|
||||
match (mrh_address.clone(), req.amount.clone()) {
|
||||
(Some(lbtc_address), Some(PayAmount::Drain)) => {
|
||||
// The BOLT11 invoice has an MRH and it is requested that the wallet balance is to be drained,
|
||||
// therefore we use the MRH address and drain the balance (overpaying the invoice if neccessary)
|
||||
let drain_fees_sat = self
|
||||
.estimate_drain_tx_fee(None, Some(&lbtc_address))
|
||||
.await?;
|
||||
let drain_amount_sat =
|
||||
get_info_res.wallet_info.balance_sat - drain_fees_sat;
|
||||
let payment_destination = SendDestination::LiquidAddress {
|
||||
address_data: LiquidAddressData {
|
||||
address: lbtc_address,
|
||||
asset_id: Some(asset_id.clone()),
|
||||
amount: None,
|
||||
amount_sat: Some(drain_amount_sat),
|
||||
network: self.config.network.into(),
|
||||
label: None,
|
||||
message: None,
|
||||
},
|
||||
bip353_address: None,
|
||||
};
|
||||
(drain_amount_sat, Some(drain_fees_sat), payment_destination)
|
||||
}
|
||||
(Some(lbtc_address), _) => {
|
||||
// The BOLT11 invoice has an MRH but no drain is requested,
|
||||
// so we calculate the fees of a direct Liquid transaction
|
||||
let fees_sat = self
|
||||
.estimate_onchain_tx_or_drain_tx_fee(
|
||||
invoice_amount_sat,
|
||||
&lbtc_address,
|
||||
&asset_id,
|
||||
)
|
||||
.await?;
|
||||
(
|
||||
(receiver_amount_sat, fees_sat) = match (mrh_address.clone(), req.amount.clone()) {
|
||||
(Some(lbtc_address), Some(PayAmount::Drain)) => {
|
||||
// The BOLT11 invoice has an MRH and it is requested that the
|
||||
// wallet balance is to be drained, so we calculate the fees of
|
||||
// a direct Liquid drain transaction
|
||||
let drain_fees_sat = self
|
||||
.estimate_drain_tx_fee(None, Some(&lbtc_address))
|
||||
.await?;
|
||||
let drain_amount_sat =
|
||||
get_info_res.wallet_info.balance_sat - drain_fees_sat;
|
||||
(drain_amount_sat, Some(drain_fees_sat))
|
||||
}
|
||||
(Some(lbtc_address), _) => {
|
||||
// The BOLT11 invoice has an MRH but no drain is requested,
|
||||
// so we calculate the fees of a direct Liquid transaction
|
||||
let fees_sat = self
|
||||
.estimate_onchain_tx_or_drain_tx_fee(
|
||||
invoice_amount_sat,
|
||||
Some(fees_sat),
|
||||
SendDestination::Bolt11 {
|
||||
invoice,
|
||||
bip353_address: None,
|
||||
},
|
||||
&lbtc_address,
|
||||
&asset_id,
|
||||
)
|
||||
}
|
||||
(None, _) => {
|
||||
// The BOLT11 invoice has no MRH, so we calculate the fees using a swap
|
||||
let boltz_fees_total = lbtc_pair.fees.total(invoice_amount_sat);
|
||||
let user_lockup_amount_sat = invoice_amount_sat + boltz_fees_total;
|
||||
let lockup_fees_sat = self
|
||||
.estimate_lockup_tx_or_drain_tx_fee(user_lockup_amount_sat)
|
||||
.await?;
|
||||
let fees_sat = boltz_fees_total + lockup_fees_sat;
|
||||
(
|
||||
invoice_amount_sat,
|
||||
Some(fees_sat),
|
||||
SendDestination::Bolt11 {
|
||||
invoice,
|
||||
bip353_address: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
.await?;
|
||||
(invoice_amount_sat, Some(fees_sat))
|
||||
}
|
||||
(None, _) => {
|
||||
// The BOLT11 invoice has no MRH, so we calculate the fees using a swap
|
||||
let boltz_fees_total = lbtc_pair.fees.total(invoice_amount_sat);
|
||||
let user_lockup_amount_sat = invoice_amount_sat + boltz_fees_total;
|
||||
let lockup_fees_sat = self
|
||||
.estimate_lockup_tx_or_drain_tx_fee(user_lockup_amount_sat)
|
||||
.await?;
|
||||
let fees_sat = boltz_fees_total + lockup_fees_sat;
|
||||
(invoice_amount_sat, Some(fees_sat))
|
||||
}
|
||||
};
|
||||
|
||||
payment_destination = SendDestination::Bolt11 {
|
||||
invoice,
|
||||
bip353_address: None,
|
||||
};
|
||||
}
|
||||
Ok(InputType::Bolt12Offer {
|
||||
offer,
|
||||
bip353_address,
|
||||
}) => {
|
||||
receiver_amount_sat = match req.amount {
|
||||
asset_id = self.config.lbtc_asset_id();
|
||||
estimated_asset_fees = None;
|
||||
(receiver_amount_sat, fees_sat) = match req.amount {
|
||||
Some(PayAmount::Drain) => {
|
||||
ensure_sdk!(
|
||||
get_info_res.wallet_info.pending_receive_sat == 0
|
||||
&& get_info_res.wallet_info.pending_send_sat == 0,
|
||||
PaymentError::Generic {
|
||||
err: "Cannot drain while there are pending payments".to_string(),
|
||||
}
|
||||
);
|
||||
let lbtc_pair = self
|
||||
.swapper
|
||||
.get_submarine_pairs()
|
||||
.await?
|
||||
.ok_or(PaymentError::PairsNotFound)?;
|
||||
let drain_fees_sat = self.estimate_drain_tx_fee(None, None).await?;
|
||||
let drain_amount_sat =
|
||||
get_info_res.wallet_info.balance_sat - drain_fees_sat;
|
||||
// Get the inverse receiver amount by calculating a dummy amount then increment up to the drain amount
|
||||
let dummy_fees_sat = lbtc_pair.fees.total(drain_amount_sat);
|
||||
let dummy_amount_sat = drain_amount_sat - dummy_fees_sat;
|
||||
let receiver_amount_sat =
|
||||
utils::increment_receiver_amount_up_to_drain_amount(
|
||||
dummy_amount_sat,
|
||||
&lbtc_pair,
|
||||
drain_amount_sat,
|
||||
);
|
||||
lbtc_pair.limits.within(receiver_amount_sat)?;
|
||||
// Validate if we can actually drain the wallet with a swap
|
||||
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
||||
ensure_sdk!(
|
||||
receiver_amount_sat + boltz_fees_total == drain_amount_sat,
|
||||
PaymentError::Generic {
|
||||
err: "Cannot drain without leaving a remainder".to_string(),
|
||||
}
|
||||
);
|
||||
let fees_sat = Some(boltz_fees_total + drain_fees_sat);
|
||||
info!("Drain amount: {receiver_amount_sat} sat");
|
||||
Ok((receiver_amount_sat, fees_sat))
|
||||
}
|
||||
Some(PayAmount::Bitcoin {
|
||||
receiver_amount_sat: amount_sat,
|
||||
}) => Ok(amount_sat),
|
||||
receiver_amount_sat,
|
||||
}) => {
|
||||
let lbtc_pair = self.validate_submarine_pairs(receiver_amount_sat).await?;
|
||||
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
||||
let lockup_fees_sat = self
|
||||
.estimate_lockup_tx_or_drain_tx_fee(
|
||||
receiver_amount_sat + boltz_fees_total,
|
||||
)
|
||||
.await?;
|
||||
let fees_sat = Some(boltz_fees_total + lockup_fees_sat);
|
||||
Ok((receiver_amount_sat, fees_sat))
|
||||
}
|
||||
_ => Err(PaymentError::amount_missing(
|
||||
"Expected PayAmount of type Receiver when processing a Bolt12 offer",
|
||||
)),
|
||||
@@ -1482,16 +1512,6 @@ impl LiquidSdk {
|
||||
);
|
||||
}
|
||||
|
||||
let lbtc_pair = self.validate_submarine_pairs(receiver_amount_sat).await?;
|
||||
|
||||
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
||||
let lockup_fees_sat = self
|
||||
.estimate_lockup_tx_or_drain_tx_fee(receiver_amount_sat + boltz_fees_total)
|
||||
.await?;
|
||||
asset_id = self.config.lbtc_asset_id();
|
||||
fees_sat = Some(boltz_fees_total + lockup_fees_sat);
|
||||
estimated_asset_fees = None;
|
||||
|
||||
payment_destination = SendDestination::Bolt12 {
|
||||
offer,
|
||||
receiver_amount_sat,
|
||||
@@ -1514,6 +1534,7 @@ impl LiquidSdk {
|
||||
destination: payment_destination,
|
||||
fees_sat,
|
||||
estimated_asset_fees,
|
||||
amount: req.amount.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1548,8 +1569,10 @@ impl LiquidSdk {
|
||||
let PrepareSendResponse {
|
||||
fees_sat,
|
||||
destination: payment_destination,
|
||||
amount,
|
||||
..
|
||||
} = &req.prepare_response;
|
||||
let is_drain = matches!(amount, Some(PayAmount::Drain));
|
||||
|
||||
match payment_destination {
|
||||
SendDestination::LiquidAddress {
|
||||
@@ -1606,7 +1629,9 @@ impl LiquidSdk {
|
||||
bip353_address,
|
||||
} => {
|
||||
let fees_sat = fees_sat.ok_or(PaymentError::InsufficientFunds)?;
|
||||
let mut response = self.pay_bolt11_invoice(&invoice.bolt11, fees_sat).await?;
|
||||
let mut response = self
|
||||
.pay_bolt11_invoice(&invoice.bolt11, fees_sat, is_drain)
|
||||
.await?;
|
||||
self.insert_bip353_payment_details(bip353_address, &mut response)?;
|
||||
Ok(response)
|
||||
}
|
||||
@@ -1621,7 +1646,13 @@ impl LiquidSdk {
|
||||
.get_bolt12_info(&offer.offer, *receiver_amount_sat)
|
||||
.await?;
|
||||
let mut response = self
|
||||
.pay_bolt12_invoice(offer, *receiver_amount_sat, bolt12_info, fees_sat)
|
||||
.pay_bolt12_invoice(
|
||||
offer,
|
||||
*receiver_amount_sat,
|
||||
bolt12_info,
|
||||
fees_sat,
|
||||
is_drain,
|
||||
)
|
||||
.await?;
|
||||
self.insert_bip353_payment_details(bip353_address, &mut response)?;
|
||||
Ok(response)
|
||||
@@ -1660,6 +1691,7 @@ impl LiquidSdk {
|
||||
&self,
|
||||
invoice: &str,
|
||||
fees_sat: u64,
|
||||
is_drain: bool,
|
||||
) -> Result<SendPaymentResponse, PaymentError> {
|
||||
self.ensure_send_is_not_self_transfer(invoice)?;
|
||||
let bolt11_invoice = self.validate_bolt11_invoice(invoice)?;
|
||||
@@ -1671,8 +1703,9 @@ impl LiquidSdk {
|
||||
err: "Invoice amount is missing".to_string(),
|
||||
})?;
|
||||
let payer_amount_sat = amount_sat + fees_sat;
|
||||
let get_info_response = self.get_info().await?;
|
||||
ensure_sdk!(
|
||||
payer_amount_sat <= self.get_info().await?.wallet_info.balance_sat,
|
||||
payer_amount_sat <= get_info_response.wallet_info.balance_sat,
|
||||
PaymentError::InsufficientFunds
|
||||
);
|
||||
|
||||
@@ -1685,6 +1718,16 @@ impl LiquidSdk {
|
||||
// If we find a valid MRH, extract the BIP21 address and pay to it via onchain tx
|
||||
Some((address, _)) => {
|
||||
info!("Found MRH for L-BTC address {address}, invoice amount_sat {amount_sat}");
|
||||
let (amount_sat, fees_sat) = if is_drain {
|
||||
let drain_fees_sat = self.estimate_drain_tx_fee(None, Some(&address)).await?;
|
||||
let drain_amount_sat =
|
||||
get_info_response.wallet_info.balance_sat - drain_fees_sat;
|
||||
info!("Drain amount: {drain_amount_sat} sat");
|
||||
(drain_amount_sat, drain_fees_sat)
|
||||
} else {
|
||||
(amount_sat, fees_sat)
|
||||
};
|
||||
|
||||
self.pay_liquid(
|
||||
LiquidAddressData {
|
||||
address,
|
||||
@@ -1723,6 +1766,7 @@ impl LiquidSdk {
|
||||
user_specified_receiver_amount_sat: u64,
|
||||
bolt12_info: GetBolt12FetchResponse,
|
||||
fees_sat: u64,
|
||||
is_drain: bool,
|
||||
) -> Result<SendPaymentResponse, PaymentError> {
|
||||
let invoice = self.validate_bolt12_invoice(
|
||||
offer,
|
||||
@@ -1732,8 +1776,9 @@ impl LiquidSdk {
|
||||
|
||||
let receiver_amount_sat = invoice.amount_msats() / 1_000;
|
||||
let payer_amount_sat = receiver_amount_sat + fees_sat;
|
||||
let get_info_response = self.get_info().await?;
|
||||
ensure_sdk!(
|
||||
payer_amount_sat <= self.get_info().await?.wallet_info.balance_sat,
|
||||
payer_amount_sat <= get_info_response.wallet_info.balance_sat,
|
||||
PaymentError::InsufficientFunds
|
||||
);
|
||||
|
||||
@@ -1745,6 +1790,15 @@ impl LiquidSdk {
|
||||
);
|
||||
let signing_pubkey = invoice.signing_pubkey().to_string();
|
||||
let (_, address, _, _) = verify_mrh_signature(&bip21, &signing_pubkey, &signature)?;
|
||||
let (receiver_amount_sat, fees_sat) = if is_drain {
|
||||
let drain_fees_sat = self.estimate_drain_tx_fee(None, Some(&address)).await?;
|
||||
let drain_amount_sat =
|
||||
get_info_response.wallet_info.balance_sat - drain_fees_sat;
|
||||
info!("Drain amount: {drain_amount_sat} sat");
|
||||
(drain_amount_sat, drain_fees_sat)
|
||||
} else {
|
||||
(receiver_amount_sat, fees_sat)
|
||||
};
|
||||
|
||||
self.pay_liquid(
|
||||
LiquidAddressData {
|
||||
@@ -4020,10 +4074,10 @@ impl LiquidSdk {
|
||||
///
|
||||
/// * `req` - the [PrepareLnUrlPayRequest] containing:
|
||||
/// * `data` - the [LnUrlPayRequestData] returned by [LiquidSdk::parse]
|
||||
/// * `amount` - The optional amount of type [PayAmount].
|
||||
/// - [PayAmount::Drain] which uses all funds
|
||||
/// - [PayAmount::Receiver] which sets the amount the receiver should receive
|
||||
/// * `bip353_address` - A BIP353 address, in case one was used in order to fetch the LNURL
|
||||
/// * `amount` - the [PayAmount] to send:
|
||||
/// - [PayAmount::Drain] which uses all Bitcoin funds
|
||||
/// - [PayAmount::Bitcoin] which sets the amount in satoshi that will be received
|
||||
/// * `bip353_address` - a BIP353 address, in case one was used in order to fetch the LNURL
|
||||
/// Pay request data. Returned by [parse].
|
||||
/// * `comment` - an optional comment for this payment
|
||||
/// * `validate_success_action_url` - validates that, if there is a URL success action, the URL domain matches
|
||||
@@ -4032,9 +4086,10 @@ impl LiquidSdk {
|
||||
/// # Returns
|
||||
/// Returns a [PrepareLnUrlPayResponse] containing:
|
||||
/// * `destination` - the destination of the payment
|
||||
/// * `fees_sat` - The fees in satoshis to send the payment
|
||||
/// * `data` - The [LnUrlPayRequestData] returned by [parse]
|
||||
/// * `comment` - An optional comment for this payment
|
||||
/// * `amount` - the [PayAmount] to send
|
||||
/// * `fees_sat` - the fees in satoshis to send the payment
|
||||
/// * `data` - the [LnUrlPayRequestData] returned by [parse]
|
||||
/// * `comment` - an optional comment for this payment
|
||||
/// * `success_action` - the optional unprocessed LUD-09 success action
|
||||
pub async fn prepare_lnurl_pay(
|
||||
&self,
|
||||
@@ -4060,28 +4115,28 @@ impl LiquidSdk {
|
||||
.ok_or(PaymentError::PairsNotFound)?;
|
||||
let drain_fees_sat = self.estimate_drain_tx_fee(None, None).await?;
|
||||
let drain_amount_sat = get_info_res.wallet_info.balance_sat - drain_fees_sat;
|
||||
// Get the inverse invoice amount by calculating a dummy amount then increment up to the drain amount
|
||||
// Get the inverse receiver amount by calculating a dummy amount then increment up to the drain amount
|
||||
let dummy_fees_sat = lbtc_pair.fees.total(drain_amount_sat);
|
||||
let dummy_amount_sat = drain_amount_sat - dummy_fees_sat;
|
||||
let invoice_amount_sat = utils::increment_invoice_amount_up_to_drain_amount(
|
||||
let receiver_amount_sat = utils::increment_receiver_amount_up_to_drain_amount(
|
||||
dummy_amount_sat,
|
||||
&lbtc_pair,
|
||||
drain_amount_sat,
|
||||
);
|
||||
lbtc_pair
|
||||
.limits
|
||||
.within(invoice_amount_sat)
|
||||
.within(receiver_amount_sat)
|
||||
.map_err(|e| LnUrlPayError::Generic { err: e.message() })?;
|
||||
// Validate if we can actually drain the wallet with a swap
|
||||
let pair_fees_sat = lbtc_pair.fees.total(invoice_amount_sat);
|
||||
let pair_fees_sat = lbtc_pair.fees.total(receiver_amount_sat);
|
||||
ensure_sdk!(
|
||||
invoice_amount_sat + pair_fees_sat == drain_amount_sat,
|
||||
receiver_amount_sat + pair_fees_sat == drain_amount_sat,
|
||||
LnUrlPayError::Generic {
|
||||
err: "Cannot drain without leaving a remainder".to_string(),
|
||||
}
|
||||
);
|
||||
|
||||
invoice_amount_sat * 1000
|
||||
receiver_amount_sat * 1000
|
||||
}
|
||||
PayAmount::Bitcoin {
|
||||
receiver_amount_sat,
|
||||
@@ -4110,7 +4165,7 @@ impl LiquidSdk {
|
||||
let prepare_response = self
|
||||
.prepare_send_payment(&PrepareSendRequest {
|
||||
destination: data.pr.clone(),
|
||||
amount: Some(req.amount),
|
||||
amount: Some(req.amount.clone()),
|
||||
})
|
||||
.await
|
||||
.map_err(|e| LnUrlPayError::Generic { err: e.to_string() })?;
|
||||
@@ -4136,6 +4191,7 @@ impl LiquidSdk {
|
||||
destination,
|
||||
fees_sat,
|
||||
data: req.data,
|
||||
amount: req.amount,
|
||||
comment: req.comment,
|
||||
success_action: data.success_action,
|
||||
})
|
||||
@@ -4166,6 +4222,7 @@ impl LiquidSdk {
|
||||
destination: prepare_response.destination.clone(),
|
||||
fees_sat: Some(prepare_response.fees_sat),
|
||||
estimated_asset_fees: None,
|
||||
amount: Some(prepare_response.amount),
|
||||
},
|
||||
use_asset_fees: None,
|
||||
})
|
||||
|
||||
@@ -151,23 +151,23 @@ pub(crate) fn lbtc_asset_id(network: LiquidNetwork) -> AssetId {
|
||||
}
|
||||
}
|
||||
|
||||
/// Increments the inversely calculated invoice amount up to the maximum drainable amount,
|
||||
/// as calculating the inverse invoice amount in some cases has rounding down errors
|
||||
pub(crate) fn increment_invoice_amount_up_to_drain_amount(
|
||||
invoice_amount_sat: u64,
|
||||
/// Increments the inversely calculated receiver amount up to the maximum drainable amount,
|
||||
/// as calculating the inverse receiver amount in some cases has rounding down errors
|
||||
pub(crate) fn increment_receiver_amount_up_to_drain_amount(
|
||||
receiver_amount_sat: u64,
|
||||
lbtc_pair: &SubmarinePair,
|
||||
drain_amount_sat: u64,
|
||||
) -> u64 {
|
||||
let incremented_amount_sat = invoice_amount_sat + 1;
|
||||
let incremented_amount_sat = receiver_amount_sat + 1;
|
||||
let fees_sat = lbtc_pair.fees.total(incremented_amount_sat);
|
||||
if incremented_amount_sat + fees_sat <= drain_amount_sat {
|
||||
increment_invoice_amount_up_to_drain_amount(
|
||||
increment_receiver_amount_up_to_drain_amount(
|
||||
incremented_amount_sat,
|
||||
lbtc_pair,
|
||||
drain_amount_sat,
|
||||
)
|
||||
} else {
|
||||
invoice_amount_sat
|
||||
receiver_amount_sat
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -457,6 +457,7 @@ pub enum SendDestination {
|
||||
#[sdk_macros::extern_wasm_bindgen(breez_sdk_liquid::prelude::PrepareSendResponse)]
|
||||
pub struct PrepareSendResponse {
|
||||
pub destination: SendDestination,
|
||||
pub amount: Option<PayAmount>,
|
||||
pub fees_sat: Option<u64>,
|
||||
pub estimated_asset_fees: Option<f64>,
|
||||
}
|
||||
@@ -789,6 +790,7 @@ pub struct PrepareLnUrlPayResponse {
|
||||
pub destination: SendDestination,
|
||||
pub fees_sat: u64,
|
||||
pub data: LnUrlPayRequestData,
|
||||
pub amount: PayAmount,
|
||||
pub comment: Option<String>,
|
||||
pub success_action: Option<SuccessAction>,
|
||||
}
|
||||
|
||||
@@ -2986,13 +2986,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
PrepareLnUrlPayResponse dco_decode_prepare_ln_url_pay_response(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
final arr = raw as List<dynamic>;
|
||||
if (arr.length != 5) throw Exception('unexpected arr length: expect 5 but see ${arr.length}');
|
||||
if (arr.length != 6) throw Exception('unexpected arr length: expect 6 but see ${arr.length}');
|
||||
return PrepareLnUrlPayResponse(
|
||||
destination: dco_decode_send_destination(arr[0]),
|
||||
feesSat: dco_decode_u_64(arr[1]),
|
||||
data: dco_decode_ln_url_pay_request_data(arr[2]),
|
||||
comment: dco_decode_opt_String(arr[3]),
|
||||
successAction: dco_decode_opt_box_autoadd_success_action(arr[4]),
|
||||
amount: dco_decode_pay_amount(arr[3]),
|
||||
comment: dco_decode_opt_String(arr[4]),
|
||||
successAction: dco_decode_opt_box_autoadd_success_action(arr[5]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3084,11 +3085,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
PrepareSendResponse dco_decode_prepare_send_response(dynamic raw) {
|
||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||
final arr = raw as List<dynamic>;
|
||||
if (arr.length != 3) throw Exception('unexpected arr length: expect 3 but see ${arr.length}');
|
||||
if (arr.length != 4) throw Exception('unexpected arr length: expect 4 but see ${arr.length}');
|
||||
return PrepareSendResponse(
|
||||
destination: dco_decode_send_destination(arr[0]),
|
||||
feesSat: dco_decode_opt_box_autoadd_u_64(arr[1]),
|
||||
estimatedAssetFees: dco_decode_opt_box_autoadd_f_64(arr[2]),
|
||||
amount: dco_decode_opt_box_autoadd_pay_amount(arr[1]),
|
||||
feesSat: dco_decode_opt_box_autoadd_u_64(arr[2]),
|
||||
estimatedAssetFees: dco_decode_opt_box_autoadd_f_64(arr[3]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5404,12 +5406,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
var var_destination = sse_decode_send_destination(deserializer);
|
||||
var var_feesSat = sse_decode_u_64(deserializer);
|
||||
var var_data = sse_decode_ln_url_pay_request_data(deserializer);
|
||||
var var_amount = sse_decode_pay_amount(deserializer);
|
||||
var var_comment = sse_decode_opt_String(deserializer);
|
||||
var var_successAction = sse_decode_opt_box_autoadd_success_action(deserializer);
|
||||
return PrepareLnUrlPayResponse(
|
||||
destination: var_destination,
|
||||
feesSat: var_feesSat,
|
||||
data: var_data,
|
||||
amount: var_amount,
|
||||
comment: var_comment,
|
||||
successAction: var_successAction,
|
||||
);
|
||||
@@ -5501,10 +5505,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
PrepareSendResponse sse_decode_prepare_send_response(SseDeserializer deserializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
var var_destination = sse_decode_send_destination(deserializer);
|
||||
var var_amount = sse_decode_opt_box_autoadd_pay_amount(deserializer);
|
||||
var var_feesSat = sse_decode_opt_box_autoadd_u_64(deserializer);
|
||||
var var_estimatedAssetFees = sse_decode_opt_box_autoadd_f_64(deserializer);
|
||||
return PrepareSendResponse(
|
||||
destination: var_destination,
|
||||
amount: var_amount,
|
||||
feesSat: var_feesSat,
|
||||
estimatedAssetFees: var_estimatedAssetFees,
|
||||
);
|
||||
@@ -7683,6 +7689,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
sse_encode_send_destination(self.destination, serializer);
|
||||
sse_encode_u_64(self.feesSat, serializer);
|
||||
sse_encode_ln_url_pay_request_data(self.data, serializer);
|
||||
sse_encode_pay_amount(self.amount, serializer);
|
||||
sse_encode_opt_String(self.comment, serializer);
|
||||
sse_encode_opt_box_autoadd_success_action(self.successAction, serializer);
|
||||
}
|
||||
@@ -7747,6 +7754,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||
void sse_encode_prepare_send_response(PrepareSendResponse self, SseSerializer serializer) {
|
||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||
sse_encode_send_destination(self.destination, serializer);
|
||||
sse_encode_opt_box_autoadd_pay_amount(self.amount, serializer);
|
||||
sse_encode_opt_box_autoadd_u_64(self.feesSat, serializer);
|
||||
sse_encode_opt_box_autoadd_f_64(self.estimatedAssetFees, serializer);
|
||||
}
|
||||
|
||||
@@ -3654,6 +3654,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
cst_api_fill_to_wire_send_destination(apiObj.destination, wireObj.destination);
|
||||
wireObj.fees_sat = cst_encode_u_64(apiObj.feesSat);
|
||||
cst_api_fill_to_wire_ln_url_pay_request_data(apiObj.data, wireObj.data);
|
||||
cst_api_fill_to_wire_pay_amount(apiObj.amount, wireObj.amount);
|
||||
wireObj.comment = cst_encode_opt_String(apiObj.comment);
|
||||
wireObj.success_action = cst_encode_opt_box_autoadd_success_action(apiObj.successAction);
|
||||
}
|
||||
@@ -3734,6 +3735,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
||||
wire_cst_prepare_send_response wireObj,
|
||||
) {
|
||||
cst_api_fill_to_wire_send_destination(apiObj.destination, wireObj.destination);
|
||||
wireObj.amount = cst_encode_opt_box_autoadd_pay_amount(apiObj.amount);
|
||||
wireObj.fees_sat = cst_encode_opt_box_autoadd_u_64(apiObj.feesSat);
|
||||
wireObj.estimated_asset_fees = cst_encode_opt_box_autoadd_f_64(apiObj.estimatedAssetFees);
|
||||
}
|
||||
@@ -6701,6 +6703,33 @@ final class wire_cst_ln_url_pay_request_data extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> ln_address;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Bitcoin extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int receiver_amount_sat;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Asset extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asset_id;
|
||||
|
||||
@ffi.Double()
|
||||
external double receiver_amount;
|
||||
|
||||
external ffi.Pointer<ffi.Bool> estimate_asset_fees;
|
||||
}
|
||||
|
||||
final class PayAmountKind extends ffi.Union {
|
||||
external wire_cst_PayAmount_Bitcoin Bitcoin;
|
||||
|
||||
external wire_cst_PayAmount_Asset Asset;
|
||||
}
|
||||
|
||||
final class wire_cst_pay_amount extends ffi.Struct {
|
||||
@ffi.Int32()
|
||||
external int tag;
|
||||
|
||||
external PayAmountKind kind;
|
||||
}
|
||||
|
||||
final class wire_cst_aes_success_action_data extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> description;
|
||||
|
||||
@@ -6757,6 +6786,8 @@ final class wire_cst_prepare_ln_url_pay_response extends ffi.Struct {
|
||||
|
||||
external wire_cst_ln_url_pay_request_data data;
|
||||
|
||||
external wire_cst_pay_amount amount;
|
||||
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> comment;
|
||||
|
||||
external ffi.Pointer<wire_cst_success_action> success_action;
|
||||
@@ -6814,33 +6845,6 @@ final class wire_cst_prepare_buy_bitcoin_request extends ffi.Struct {
|
||||
external int amount_sat;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Bitcoin extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int receiver_amount_sat;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Asset extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asset_id;
|
||||
|
||||
@ffi.Double()
|
||||
external double receiver_amount;
|
||||
|
||||
external ffi.Pointer<ffi.Bool> estimate_asset_fees;
|
||||
}
|
||||
|
||||
final class PayAmountKind extends ffi.Union {
|
||||
external wire_cst_PayAmount_Bitcoin Bitcoin;
|
||||
|
||||
external wire_cst_PayAmount_Asset Asset;
|
||||
}
|
||||
|
||||
final class wire_cst_pay_amount extends ffi.Struct {
|
||||
@ffi.Int32()
|
||||
external int tag;
|
||||
|
||||
external PayAmountKind kind;
|
||||
}
|
||||
|
||||
final class wire_cst_prepare_ln_url_pay_request extends ffi.Struct {
|
||||
external wire_cst_ln_url_pay_request_data data;
|
||||
|
||||
@@ -6945,6 +6949,8 @@ final class wire_cst_restore_request extends ffi.Struct {
|
||||
final class wire_cst_prepare_send_response extends ffi.Struct {
|
||||
external wire_cst_send_destination destination;
|
||||
|
||||
external ffi.Pointer<wire_cst_pay_amount> amount;
|
||||
|
||||
external ffi.Pointer<ffi.Uint64> fees_sat;
|
||||
|
||||
external ffi.Pointer<ffi.Double> estimated_asset_fees;
|
||||
|
||||
@@ -1187,6 +1187,9 @@ class PrepareLnUrlPayResponse {
|
||||
/// The [LnUrlPayRequestData] returned by [parse]
|
||||
final LnUrlPayRequestData data;
|
||||
|
||||
/// The amount to send
|
||||
final PayAmount amount;
|
||||
|
||||
/// An optional comment for this payment
|
||||
final String? comment;
|
||||
|
||||
@@ -1198,13 +1201,19 @@ class PrepareLnUrlPayResponse {
|
||||
required this.destination,
|
||||
required this.feesSat,
|
||||
required this.data,
|
||||
required this.amount,
|
||||
this.comment,
|
||||
this.successAction,
|
||||
});
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
destination.hashCode ^ feesSat.hashCode ^ data.hashCode ^ comment.hashCode ^ successAction.hashCode;
|
||||
destination.hashCode ^
|
||||
feesSat.hashCode ^
|
||||
data.hashCode ^
|
||||
amount.hashCode ^
|
||||
comment.hashCode ^
|
||||
successAction.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
@@ -1214,6 +1223,7 @@ class PrepareLnUrlPayResponse {
|
||||
destination == other.destination &&
|
||||
feesSat == other.feesSat &&
|
||||
data == other.data &&
|
||||
amount == other.amount &&
|
||||
comment == other.comment &&
|
||||
successAction == other.successAction;
|
||||
}
|
||||
@@ -1430,6 +1440,9 @@ class PrepareSendRequest {
|
||||
class PrepareSendResponse {
|
||||
final SendDestination destination;
|
||||
|
||||
/// The optional amount to be sent in either Bitcoin or another asset
|
||||
final PayAmount? amount;
|
||||
|
||||
/// The optional estimated fee in satoshi. Is set when there is Bitcoin available
|
||||
/// to pay fees. When not set, there are asset fees available to pay fees.
|
||||
final BigInt? feesSat;
|
||||
@@ -1439,10 +1452,10 @@ class PrepareSendResponse {
|
||||
/// are funds available in this asset to pay fees.
|
||||
final double? estimatedAssetFees;
|
||||
|
||||
const PrepareSendResponse({required this.destination, this.feesSat, this.estimatedAssetFees});
|
||||
const PrepareSendResponse({required this.destination, this.amount, this.feesSat, this.estimatedAssetFees});
|
||||
|
||||
@override
|
||||
int get hashCode => destination.hashCode ^ feesSat.hashCode ^ estimatedAssetFees.hashCode;
|
||||
int get hashCode => destination.hashCode ^ amount.hashCode ^ feesSat.hashCode ^ estimatedAssetFees.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
@@ -1450,6 +1463,7 @@ class PrepareSendResponse {
|
||||
other is PrepareSendResponse &&
|
||||
runtimeType == other.runtimeType &&
|
||||
destination == other.destination &&
|
||||
amount == other.amount &&
|
||||
feesSat == other.feesSat &&
|
||||
estimatedAssetFees == other.estimatedAssetFees;
|
||||
}
|
||||
|
||||
@@ -4550,6 +4550,33 @@ final class wire_cst_ln_url_pay_request_data extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> ln_address;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Bitcoin extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int receiver_amount_sat;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Asset extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asset_id;
|
||||
|
||||
@ffi.Double()
|
||||
external double receiver_amount;
|
||||
|
||||
external ffi.Pointer<ffi.Bool> estimate_asset_fees;
|
||||
}
|
||||
|
||||
final class PayAmountKind extends ffi.Union {
|
||||
external wire_cst_PayAmount_Bitcoin Bitcoin;
|
||||
|
||||
external wire_cst_PayAmount_Asset Asset;
|
||||
}
|
||||
|
||||
final class wire_cst_pay_amount extends ffi.Struct {
|
||||
@ffi.Int32()
|
||||
external int tag;
|
||||
|
||||
external PayAmountKind kind;
|
||||
}
|
||||
|
||||
final class wire_cst_aes_success_action_data extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> description;
|
||||
|
||||
@@ -4606,6 +4633,8 @@ final class wire_cst_prepare_ln_url_pay_response extends ffi.Struct {
|
||||
|
||||
external wire_cst_ln_url_pay_request_data data;
|
||||
|
||||
external wire_cst_pay_amount amount;
|
||||
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> comment;
|
||||
|
||||
external ffi.Pointer<wire_cst_success_action> success_action;
|
||||
@@ -4663,33 +4692,6 @@ final class wire_cst_prepare_buy_bitcoin_request extends ffi.Struct {
|
||||
external int amount_sat;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Bitcoin extends ffi.Struct {
|
||||
@ffi.Uint64()
|
||||
external int receiver_amount_sat;
|
||||
}
|
||||
|
||||
final class wire_cst_PayAmount_Asset extends ffi.Struct {
|
||||
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asset_id;
|
||||
|
||||
@ffi.Double()
|
||||
external double receiver_amount;
|
||||
|
||||
external ffi.Pointer<ffi.Bool> estimate_asset_fees;
|
||||
}
|
||||
|
||||
final class PayAmountKind extends ffi.Union {
|
||||
external wire_cst_PayAmount_Bitcoin Bitcoin;
|
||||
|
||||
external wire_cst_PayAmount_Asset Asset;
|
||||
}
|
||||
|
||||
final class wire_cst_pay_amount extends ffi.Struct {
|
||||
@ffi.Int32()
|
||||
external int tag;
|
||||
|
||||
external PayAmountKind kind;
|
||||
}
|
||||
|
||||
final class wire_cst_prepare_ln_url_pay_request extends ffi.Struct {
|
||||
external wire_cst_ln_url_pay_request_data data;
|
||||
|
||||
@@ -4794,6 +4796,8 @@ final class wire_cst_restore_request extends ffi.Struct {
|
||||
final class wire_cst_prepare_send_response extends ffi.Struct {
|
||||
external wire_cst_send_destination destination;
|
||||
|
||||
external ffi.Pointer<wire_cst_pay_amount> amount;
|
||||
|
||||
external ffi.Pointer<ffi.Uint64> fees_sat;
|
||||
|
||||
external ffi.Pointer<ffi.Double> estimated_asset_fees;
|
||||
|
||||
@@ -2003,6 +2003,7 @@ fun asPrepareLnUrlPayResponse(prepareLnUrlPayResponse: ReadableMap): PrepareLnUr
|
||||
"destination",
|
||||
"feesSat",
|
||||
"data",
|
||||
"amount",
|
||||
),
|
||||
)
|
||||
) {
|
||||
@@ -2011,6 +2012,7 @@ fun asPrepareLnUrlPayResponse(prepareLnUrlPayResponse: ReadableMap): PrepareLnUr
|
||||
val destination = prepareLnUrlPayResponse.getMap("destination")?.let { asSendDestination(it) }!!
|
||||
val feesSat = prepareLnUrlPayResponse.getDouble("feesSat").toULong()
|
||||
val data = prepareLnUrlPayResponse.getMap("data")?.let { asLnUrlPayRequestData(it) }!!
|
||||
val amount = prepareLnUrlPayResponse.getMap("amount")?.let { asPayAmount(it) }!!
|
||||
val comment = if (hasNonNullKey(prepareLnUrlPayResponse, "comment")) prepareLnUrlPayResponse.getString("comment") else null
|
||||
val successAction =
|
||||
if (hasNonNullKey(prepareLnUrlPayResponse, "successAction")) {
|
||||
@@ -2020,7 +2022,7 @@ fun asPrepareLnUrlPayResponse(prepareLnUrlPayResponse: ReadableMap): PrepareLnUr
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return PrepareLnUrlPayResponse(destination, feesSat, data, comment, successAction)
|
||||
return PrepareLnUrlPayResponse(destination, feesSat, data, amount, comment, successAction)
|
||||
}
|
||||
|
||||
fun readableMapOf(prepareLnUrlPayResponse: PrepareLnUrlPayResponse): ReadableMap =
|
||||
@@ -2028,6 +2030,7 @@ fun readableMapOf(prepareLnUrlPayResponse: PrepareLnUrlPayResponse): ReadableMap
|
||||
"destination" to readableMapOf(prepareLnUrlPayResponse.destination),
|
||||
"feesSat" to prepareLnUrlPayResponse.feesSat,
|
||||
"data" to readableMapOf(prepareLnUrlPayResponse.data),
|
||||
"amount" to readableMapOf(prepareLnUrlPayResponse.amount),
|
||||
"comment" to prepareLnUrlPayResponse.comment,
|
||||
"successAction" to prepareLnUrlPayResponse.successAction?.let { readableMapOf(it) },
|
||||
)
|
||||
@@ -2357,6 +2360,7 @@ fun asPrepareSendResponse(prepareSendResponse: ReadableMap): PrepareSendResponse
|
||||
return null
|
||||
}
|
||||
val destination = prepareSendResponse.getMap("destination")?.let { asSendDestination(it) }!!
|
||||
val amount = if (hasNonNullKey(prepareSendResponse, "amount")) prepareSendResponse.getMap("amount")?.let { asPayAmount(it) } else null
|
||||
val feesSat = if (hasNonNullKey(prepareSendResponse, "feesSat")) prepareSendResponse.getDouble("feesSat").toULong() else null
|
||||
val estimatedAssetFees =
|
||||
if (hasNonNullKey(
|
||||
@@ -2368,12 +2372,13 @@ fun asPrepareSendResponse(prepareSendResponse: ReadableMap): PrepareSendResponse
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return PrepareSendResponse(destination, feesSat, estimatedAssetFees)
|
||||
return PrepareSendResponse(destination, amount, feesSat, estimatedAssetFees)
|
||||
}
|
||||
|
||||
fun readableMapOf(prepareSendResponse: PrepareSendResponse): ReadableMap =
|
||||
readableMapOf(
|
||||
"destination" to readableMapOf(prepareSendResponse.destination),
|
||||
"amount" to prepareSendResponse.amount?.let { readableMapOf(it) },
|
||||
"feesSat" to prepareSendResponse.feesSat,
|
||||
"estimatedAssetFees" to prepareSendResponse.estimatedAssetFees,
|
||||
)
|
||||
|
||||
@@ -2392,6 +2392,11 @@ enum BreezSDKLiquidMapper {
|
||||
}
|
||||
let data = try asLnUrlPayRequestData(lnUrlPayRequestData: dataTmp)
|
||||
|
||||
guard let amountTmp = prepareLnUrlPayResponse["amount"] as? [String: Any?] else {
|
||||
throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "amount", typeName: "PrepareLnUrlPayResponse"))
|
||||
}
|
||||
let amount = try asPayAmount(payAmount: amountTmp)
|
||||
|
||||
var comment: String?
|
||||
if hasNonNilKey(data: prepareLnUrlPayResponse, key: "comment") {
|
||||
guard let commentTmp = prepareLnUrlPayResponse["comment"] as? String else {
|
||||
@@ -2404,7 +2409,7 @@ enum BreezSDKLiquidMapper {
|
||||
successAction = try asSuccessAction(successAction: successActionTmp)
|
||||
}
|
||||
|
||||
return PrepareLnUrlPayResponse(destination: destination, feesSat: feesSat, data: data, comment: comment, successAction: successAction)
|
||||
return PrepareLnUrlPayResponse(destination: destination, feesSat: feesSat, data: data, amount: amount, comment: comment, successAction: successAction)
|
||||
}
|
||||
|
||||
static func dictionaryOf(prepareLnUrlPayResponse: PrepareLnUrlPayResponse) -> [String: Any?] {
|
||||
@@ -2412,6 +2417,7 @@ enum BreezSDKLiquidMapper {
|
||||
"destination": dictionaryOf(sendDestination: prepareLnUrlPayResponse.destination),
|
||||
"feesSat": prepareLnUrlPayResponse.feesSat,
|
||||
"data": dictionaryOf(lnUrlPayRequestData: prepareLnUrlPayResponse.data),
|
||||
"amount": dictionaryOf(payAmount: prepareLnUrlPayResponse.amount),
|
||||
"comment": prepareLnUrlPayResponse.comment == nil ? nil : prepareLnUrlPayResponse.comment,
|
||||
"successAction": prepareLnUrlPayResponse.successAction == nil ? nil : dictionaryOf(successAction: prepareLnUrlPayResponse.successAction!),
|
||||
]
|
||||
@@ -2743,6 +2749,11 @@ enum BreezSDKLiquidMapper {
|
||||
}
|
||||
let destination = try asSendDestination(sendDestination: destinationTmp)
|
||||
|
||||
var amount: PayAmount?
|
||||
if let amountTmp = prepareSendResponse["amount"] as? [String: Any?] {
|
||||
amount = try asPayAmount(payAmount: amountTmp)
|
||||
}
|
||||
|
||||
var feesSat: UInt64?
|
||||
if hasNonNilKey(data: prepareSendResponse, key: "feesSat") {
|
||||
guard let feesSatTmp = prepareSendResponse["feesSat"] as? UInt64 else {
|
||||
@@ -2758,12 +2769,13 @@ enum BreezSDKLiquidMapper {
|
||||
estimatedAssetFees = estimatedAssetFeesTmp
|
||||
}
|
||||
|
||||
return PrepareSendResponse(destination: destination, feesSat: feesSat, estimatedAssetFees: estimatedAssetFees)
|
||||
return PrepareSendResponse(destination: destination, amount: amount, feesSat: feesSat, estimatedAssetFees: estimatedAssetFees)
|
||||
}
|
||||
|
||||
static func dictionaryOf(prepareSendResponse: PrepareSendResponse) -> [String: Any?] {
|
||||
return [
|
||||
"destination": dictionaryOf(sendDestination: prepareSendResponse.destination),
|
||||
"amount": prepareSendResponse.amount == nil ? nil : dictionaryOf(payAmount: prepareSendResponse.amount!),
|
||||
"feesSat": prepareSendResponse.feesSat == nil ? nil : prepareSendResponse.feesSat,
|
||||
"estimatedAssetFees": prepareSendResponse.estimatedAssetFees == nil ? nil : prepareSendResponse.estimatedAssetFees,
|
||||
]
|
||||
|
||||
@@ -356,6 +356,7 @@ export interface PrepareLnUrlPayResponse {
|
||||
destination: SendDestination
|
||||
feesSat: number
|
||||
data: LnUrlPayRequestData
|
||||
amount: PayAmount
|
||||
comment?: string
|
||||
successAction?: SuccessAction
|
||||
}
|
||||
@@ -404,6 +405,7 @@ export interface PrepareSendRequest {
|
||||
|
||||
export interface PrepareSendResponse {
|
||||
destination: SendDestination
|
||||
amount?: PayAmount
|
||||
feesSat?: number
|
||||
estimatedAssetFees?: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user