diff --git a/cli/src/commands.rs b/cli/src/commands.rs index dd5ffa462..766feb5dd 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -34,8 +34,12 @@ pub(crate) enum Command { #[arg(short, long)] amount_sat: Option, - /// Delay for the send, in seconds + /// Whether or not this is a drain operation. If true, all available funds will be used. #[arg(short, long)] + drain: Option, + + /// Delay for the send, in seconds + #[arg(long)] delay: Option, }, /// Fetch the current limits for Send and Receive payments @@ -310,6 +314,7 @@ pub(crate) async fn handle_command( invoice, address, amount_sat, + drain, delay, } => { let destination = match (invoice, address) { @@ -326,11 +331,16 @@ pub(crate) async fn handle_command( )) } }; + let amount = match (amount_sat, drain.unwrap_or(false)) { + (Some(amount_sat), _) => Some(PayAmount::Receiver { amount_sat }), + (_, true) => Some(PayAmount::Drain), + (_, _) => None, + }; let prepare_response = sdk .prepare_send_payment(&PrepareSendRequest { destination, - amount_sat, + amount, }) .await?; @@ -366,8 +376,8 @@ pub(crate) async fn handle_command( fee_rate_sat_per_vbyte, } => { let amount = match drain.unwrap_or(false) { - true => PayOnchainAmount::Drain, - false => PayOnchainAmount::Receiver { + true => PayAmount::Drain, + false => PayAmount::Receiver { amount_sat: receiver_amount_sat.ok_or(anyhow::anyhow!( "Must specify `receiver_amount_sat` if not draining" ))?, diff --git a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h index d02b1bd78..e887ca4fb 100644 --- a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h +++ b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h @@ -279,21 +279,21 @@ typedef struct wire_cst_prepare_ln_url_pay_request { bool *validate_success_action_url; } wire_cst_prepare_ln_url_pay_request; -typedef struct wire_cst_PayOnchainAmount_Receiver { +typedef struct wire_cst_PayAmount_Receiver { uint64_t amount_sat; -} wire_cst_PayOnchainAmount_Receiver; +} wire_cst_PayAmount_Receiver; -typedef union PayOnchainAmountKind { - struct wire_cst_PayOnchainAmount_Receiver Receiver; -} PayOnchainAmountKind; +typedef union PayAmountKind { + struct wire_cst_PayAmount_Receiver Receiver; +} PayAmountKind; -typedef struct wire_cst_pay_onchain_amount { +typedef struct wire_cst_pay_amount { int32_t tag; - union PayOnchainAmountKind kind; -} wire_cst_pay_onchain_amount; + union PayAmountKind kind; +} wire_cst_pay_amount; typedef struct wire_cst_prepare_pay_onchain_request { - struct wire_cst_pay_onchain_amount amount; + struct wire_cst_pay_amount amount; uint32_t *fee_rate_sat_per_vbyte; } wire_cst_prepare_pay_onchain_request; @@ -310,7 +310,7 @@ typedef struct wire_cst_prepare_refund_request { typedef struct wire_cst_prepare_send_request { struct wire_cst_list_prim_u_8_strict *destination; - uint64_t *amount_sat; + struct wire_cst_pay_amount *amount; } wire_cst_prepare_send_request; typedef struct wire_cst_prepare_receive_response { @@ -1166,6 +1166,8 @@ struct wire_cst_ln_url_withdraw_success_data *frbgen_breez_liquid_cst_new_box_au struct wire_cst_message_success_action_data *frbgen_breez_liquid_cst_new_box_autoadd_message_success_action_data(void); +struct wire_cst_pay_amount *frbgen_breez_liquid_cst_new_box_autoadd_pay_amount(void); + struct wire_cst_pay_onchain_request *frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request(void); struct wire_cst_payment *frbgen_breez_liquid_cst_new_box_autoadd_payment(void); @@ -1253,6 +1255,7 @@ static int64_t dummy_method_to_enforce_bundling(void) { dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_ln_url_withdraw_request_data); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_ln_url_withdraw_success_data); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_message_success_action_data); + dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_pay_amount); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_payment); dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_prepare_buy_bitcoin_request); diff --git a/lib/bindings/src/breez_sdk_liquid.udl b/lib/bindings/src/breez_sdk_liquid.udl index 290267558..e994e7d2f 100644 --- a/lib/bindings/src/breez_sdk_liquid.udl +++ b/lib/bindings/src/breez_sdk_liquid.udl @@ -373,7 +373,7 @@ dictionary LnUrlPayRequest { dictionary PrepareSendRequest { string destination; - u64? amount_sat = null; + PayAmount? amount = null; }; [Enum] @@ -439,13 +439,13 @@ dictionary OnchainPaymentLimitsResponse { }; [Enum] -interface PayOnchainAmount { +interface PayAmount { Receiver(u64 amount_sat); Drain(); }; dictionary PreparePayOnchainRequest { - PayOnchainAmount amount; + PayAmount amount; u32? fee_rate_sat_per_vbyte = null; }; diff --git a/lib/core/src/chain_swap.rs b/lib/core/src/chain_swap.rs index 5ed31c365..a08026e96 100644 --- a/lib/core/src/chain_swap.rs +++ b/lib/core/src/chain_swap.rs @@ -612,30 +612,14 @@ impl ChainSwapHandler { lockup_details.amount, lockup_details.lockup_address ); - let lockup_tx = match self + let lockup_tx = self .onchain_wallet - .build_tx( - self.config - .lowball_fee_rate_msat_per_vbyte() - .map(|v| v as f32), + .build_tx_or_drain_tx( + self.config.lowball_fee_rate_msat_per_vbyte(), &lockup_details.lockup_address, lockup_details.amount, ) - .await - { - Err(PaymentError::InsufficientFunds) => { - warn!("Cannot build normal lockup tx due to insufficient funds, attempting to build drain tx"); - self.onchain_wallet - .build_drain_tx( - None, - &lockup_details.lockup_address, - Some(lockup_details.amount), - ) - .await - } - Err(e) => Err(e), - Ok(lockup_tx) => Ok(lockup_tx), - }?; + .await?; let lockup_tx_id = self .liquid_chain_service diff --git a/lib/core/src/frb_generated.rs b/lib/core/src/frb_generated.rs index 54c3f65aa..9e25cab2d 100644 --- a/lib/core/src/frb_generated.rs +++ b/lib/core/src/frb_generated.rs @@ -3180,6 +3180,17 @@ impl SseDecode for Option { } } +impl SseDecode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(::sse_decode(deserializer)); + } else { + return None; + } + } +} + impl SseDecode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -3259,19 +3270,19 @@ impl SseDecode for Option> { } } -impl SseDecode for crate::model::PayOnchainAmount { +impl SseDecode for crate::model::PayAmount { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { let mut tag_ = ::sse_decode(deserializer); match tag_ { 0 => { let mut var_amountSat = ::sse_decode(deserializer); - return crate::model::PayOnchainAmount::Receiver { + return crate::model::PayAmount::Receiver { amount_sat: var_amountSat, }; } 1 => { - return crate::model::PayOnchainAmount::Drain; + return crate::model::PayAmount::Drain; } _ => { unimplemented!(""); @@ -3558,7 +3569,7 @@ impl SseDecode for crate::model::PrepareLnUrlPayResponse { impl SseDecode for crate::model::PreparePayOnchainRequest { // 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_amount = ::sse_decode(deserializer); + let mut var_amount = ::sse_decode(deserializer); let mut var_feeRateSatPerVbyte = >::sse_decode(deserializer); return crate::model::PreparePayOnchainRequest { amount: var_amount, @@ -3639,10 +3650,10 @@ impl SseDecode for crate::model::PrepareSendRequest { // 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 = ::sse_decode(deserializer); - let mut var_amountSat = >::sse_decode(deserializer); + let mut var_amount = >::sse_decode(deserializer); return crate::model::PrepareSendRequest { destination: var_destination, - amount_sat: var_amountSat, + amount: var_amount, }; } } @@ -5169,27 +5180,22 @@ impl flutter_rust_bridge::IntoIntoDart flutter_rust_bridge::for_generated::DartAbi { match self { - crate::model::PayOnchainAmount::Receiver { amount_sat } => { + crate::model::PayAmount::Receiver { amount_sat } => { [0.into_dart(), amount_sat.into_into_dart().into_dart()].into_dart() } - crate::model::PayOnchainAmount::Drain => [1.into_dart()].into_dart(), + crate::model::PayAmount::Drain => [1.into_dart()].into_dart(), _ => { unimplemented!(""); } } } } -impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive - for crate::model::PayOnchainAmount -{ -} -impl flutter_rust_bridge::IntoIntoDart - for crate::model::PayOnchainAmount -{ - fn into_into_dart(self) -> crate::model::PayOnchainAmount { +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::model::PayAmount {} +impl flutter_rust_bridge::IntoIntoDart for crate::model::PayAmount { + fn into_into_dart(self) -> crate::model::PayAmount { self } } @@ -5636,7 +5642,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PrepareSendRequest { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { [ self.destination.into_into_dart().into_dart(), - self.amount_sat.into_into_dart().into_dart(), + self.amount.into_into_dart().into_dart(), ] .into_dart() } @@ -6979,6 +6985,16 @@ impl SseEncode for Option { } } +impl SseEncode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + ::sse_encode(value, serializer); + } + } +} + impl SseEncode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -7049,15 +7065,15 @@ impl SseEncode for Option> { } } -impl SseEncode for crate::model::PayOnchainAmount { +impl SseEncode for crate::model::PayAmount { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { match self { - crate::model::PayOnchainAmount::Receiver { amount_sat } => { + crate::model::PayAmount::Receiver { amount_sat } => { ::sse_encode(0, serializer); ::sse_encode(amount_sat, serializer); } - crate::model::PayOnchainAmount::Drain => { + crate::model::PayAmount::Drain => { ::sse_encode(1, serializer); } _ => { @@ -7316,7 +7332,7 @@ impl SseEncode for crate::model::PrepareLnUrlPayResponse { impl SseEncode for crate::model::PreparePayOnchainRequest { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - ::sse_encode(self.amount, serializer); + ::sse_encode(self.amount, serializer); >::sse_encode(self.fee_rate_sat_per_vbyte, serializer); } } @@ -7369,7 +7385,7 @@ impl SseEncode for crate::model::PrepareSendRequest { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { ::sse_encode(self.destination, serializer); - >::sse_encode(self.amount_sat, serializer); + >::sse_encode(self.amount, serializer); } } @@ -8036,6 +8052,13 @@ mod io { CstDecode::::cst_decode(*wrap).into() } } + impl CstDecode for *mut wire_cst_pay_amount { + // Codec=Cst (C-struct based), see doc to use other codecs + fn cst_decode(self) -> crate::model::PayAmount { + let wrap = unsafe { flutter_rust_bridge::for_generated::box_from_leak_ptr(self) }; + CstDecode::::cst_decode(*wrap).into() + } + } impl CstDecode for *mut wire_cst_pay_onchain_request { // Codec=Cst (C-struct based), see doc to use other codecs fn cst_decode(self) -> crate::model::PayOnchainRequest { @@ -8884,17 +8907,17 @@ mod io { } } } - impl CstDecode for wire_cst_pay_onchain_amount { + impl CstDecode for wire_cst_pay_amount { // Codec=Cst (C-struct based), see doc to use other codecs - fn cst_decode(self) -> crate::model::PayOnchainAmount { + fn cst_decode(self) -> crate::model::PayAmount { match self.tag { 0 => { let ans = unsafe { self.kind.Receiver }; - crate::model::PayOnchainAmount::Receiver { + crate::model::PayAmount::Receiver { amount_sat: ans.amount_sat.cst_decode(), } } - 1 => crate::model::PayOnchainAmount::Drain, + 1 => crate::model::PayAmount::Drain, _ => unreachable!(), } } @@ -9142,7 +9165,7 @@ mod io { fn cst_decode(self) -> crate::model::PrepareSendRequest { crate::model::PrepareSendRequest { destination: self.destination.cst_decode(), - amount_sat: self.amount_sat.cst_decode(), + amount: self.amount.cst_decode(), } } } @@ -10036,15 +10059,15 @@ mod io { Self::new_with_null_ptr() } } - impl NewWithNullPtr for wire_cst_pay_onchain_amount { + impl NewWithNullPtr for wire_cst_pay_amount { fn new_with_null_ptr() -> Self { Self { tag: -1, - kind: PayOnchainAmountKind { nil__: () }, + kind: PayAmountKind { nil__: () }, } } } - impl Default for wire_cst_pay_onchain_amount { + impl Default for wire_cst_pay_amount { fn default() -> Self { Self::new_with_null_ptr() } @@ -10249,7 +10272,7 @@ mod io { fn new_with_null_ptr() -> Self { Self { destination: core::ptr::null_mut(), - amount_sat: core::ptr::null_mut(), + amount: core::ptr::null_mut(), } } } @@ -11108,6 +11131,14 @@ mod io { ) } + #[no_mangle] + pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_pay_amount( + ) -> *mut wire_cst_pay_amount { + flutter_rust_bridge::for_generated::new_leak_box_ptr( + wire_cst_pay_amount::new_with_null_ptr(), + ) + } + #[no_mangle] pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request( ) -> *mut wire_cst_pay_onchain_request { @@ -12042,19 +12073,19 @@ mod io { } #[repr(C)] #[derive(Clone, Copy)] - pub struct wire_cst_pay_onchain_amount { + pub struct wire_cst_pay_amount { tag: i32, - kind: PayOnchainAmountKind, + kind: PayAmountKind, } #[repr(C)] #[derive(Clone, Copy)] - pub union PayOnchainAmountKind { - Receiver: wire_cst_PayOnchainAmount_Receiver, + pub union PayAmountKind { + Receiver: wire_cst_PayAmount_Receiver, nil__: (), } #[repr(C)] #[derive(Clone, Copy)] - pub struct wire_cst_PayOnchainAmount_Receiver { + pub struct wire_cst_PayAmount_Receiver { amount_sat: u64, } #[repr(C)] @@ -12217,7 +12248,7 @@ mod io { #[repr(C)] #[derive(Clone, Copy)] pub struct wire_cst_prepare_pay_onchain_request { - amount: wire_cst_pay_onchain_amount, + amount: wire_cst_pay_amount, fee_rate_sat_per_vbyte: *mut u32, } #[repr(C)] @@ -12258,7 +12289,7 @@ mod io { #[derive(Clone, Copy)] pub struct wire_cst_prepare_send_request { destination: *mut wire_cst_list_prim_u_8_strict, - amount_sat: *mut u64, + amount: *mut wire_cst_pay_amount, } #[repr(C)] #[derive(Clone, Copy)] diff --git a/lib/core/src/model.rs b/lib/core/src/model.rs index 467a315b3..136dd7508 100644 --- a/lib/core/src/model.rs +++ b/lib/core/src/model.rs @@ -100,9 +100,9 @@ impl Config { .unwrap_or(DEFAULT_ZERO_CONF_MAX_SAT) } - pub(crate) fn lowball_fee_rate_msat_per_vbyte(&self) -> Option { + pub(crate) fn lowball_fee_rate_msat_per_vbyte(&self) -> Option { match self.network { - LiquidNetwork::Mainnet => Some(LOWBALL_FEE_RATE_SAT_PER_VBYTE * 1000.0), + LiquidNetwork::Mainnet => Some((LOWBALL_FEE_RATE_SAT_PER_VBYTE * 1000.0) as f32), LiquidNetwork::Testnet => None, } } @@ -349,8 +349,8 @@ pub struct PrepareSendRequest { pub destination: String, /// Should only be set when paying directly onchain or to a BIP21 URI - /// where no amount is specified - pub amount_sat: Option, + /// where no amount is specified, or when the caller wishes to drain + pub amount: Option, } /// Specifies the supported destinations which can be payed by the SDK @@ -384,7 +384,7 @@ pub struct SendPaymentResponse { } #[derive(Debug, Serialize, Clone)] -pub enum PayOnchainAmount { +pub enum PayAmount { /// The amount in satoshi that will be received Receiver { amount_sat: u64 }, /// Indicates that all available funds should be sent @@ -394,7 +394,7 @@ pub enum PayOnchainAmount { /// An argument when calling [crate::sdk::LiquidSdk::prepare_pay_onchain]. #[derive(Debug, Serialize, Clone)] pub struct PreparePayOnchainRequest { - pub amount: PayOnchainAmount, + pub amount: PayAmount, /// The optional fee rate of the Bitcoin claim transaction in sat/vB. Defaults to the swapper estimated claim fee. pub fee_rate_sat_per_vbyte: Option, } diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs index b53edbb88..81d7638d9 100644 --- a/lib/core/src/sdk.rs +++ b/lib/core/src/sdk.rs @@ -643,10 +643,7 @@ impl LiquidSdk { amount_sat: u64, address: &str, ) -> Result { - let fee_rate_msat_per_vbyte = self - .config - .lowball_fee_rate_msat_per_vbyte() - .map(|v| v as f32); + let fee_rate_msat_per_vbyte = self.config.lowball_fee_rate_msat_per_vbyte(); Ok(self .onchain_wallet .build_tx(fee_rate_msat_per_vbyte, address, amount_sat) @@ -665,34 +662,30 @@ impl LiquidSdk { } } - /// Estimate the lockup tx fee for Send swaps - async fn estimate_lockup_tx_fee_send( + /// Estimate the lockup tx fee for Send and Chain Send swaps + async fn estimate_lockup_tx_fee( &self, user_lockup_amount_sat: u64, ) -> Result { let temp_p2tr_addr = self.get_temp_p2tr_addr(); - self.estimate_onchain_tx_fee(user_lockup_amount_sat, temp_p2tr_addr) .await } - /// Estimate the lockup tx fee for Chain Send swaps - async fn estimate_lockup_tx_fee_chain_send( + async fn estimate_drain_tx_fee( &self, - user_lockup_amount_sat: u64, + enforce_amount_sat: Option, + address: Option<&str>, ) -> Result { - let temp_p2tr_addr = self.get_temp_p2tr_addr(); - - self.estimate_onchain_tx_fee(user_lockup_amount_sat, temp_p2tr_addr) - .await - } - - async fn estimate_drain_tx_fee(&self) -> Result { - let temp_p2tr_addr = self.get_temp_p2tr_addr(); - + let receipent_address = address.unwrap_or(self.get_temp_p2tr_addr()); + let fee_rate_msat_per_vbyte = self.config.lowball_fee_rate_msat_per_vbyte(); let fee_sat = self .onchain_wallet - .build_drain_tx(None, temp_p2tr_addr, None) + .build_drain_tx( + fee_rate_msat_per_vbyte, + receipent_address, + enforce_amount_sat, + ) .await? .all_fees() .values() @@ -702,13 +695,40 @@ impl LiquidSdk { Ok(fee_sat) } + async fn estimate_onchain_tx_or_drain_tx_fee( + &self, + amount_sat: u64, + address: &str, + ) -> Result { + match self.estimate_onchain_tx_fee(amount_sat, address).await { + Ok(fees_sat) => Ok(fees_sat), + Err(PaymentError::InsufficientFunds) => self + .estimate_drain_tx_fee(Some(amount_sat), Some(address)) + .await + .map_err(|_| PaymentError::InsufficientFunds), + Err(e) => Err(e), + } + } + + async fn estimate_lockup_tx_or_drain_tx_fee( + &self, + amount_sat: u64, + ) -> Result { + let temp_p2tr_addr = self.get_temp_p2tr_addr(); + self.estimate_onchain_tx_or_drain_tx_fee(amount_sat, temp_p2tr_addr) + .await + } + /// Prepares to pay a Lightning invoice via a submarine swap. /// /// # Arguments /// /// * `req` - the [PrepareSendRequest] containing: /// * `destination` - Either a Liquid BIP21 URI/address or a BOLT11 invoice - /// * `amount_sat` - Should only be specified when paying directly onchain or via amount-less BIP21 + /// * `amount` - The optional amount of type [PayAmount]. Should only be specified + /// when paying directly onchain or via amount-less BIP21. + /// - [PayAmount::Drain] which uses all funds + /// - [PayAmount::Receiver] which sets the amount the receiver should receive /// /// # Returns /// Returns a [PrepareSendResponse] containing: @@ -720,6 +740,7 @@ impl LiquidSdk { ) -> Result { self.ensure_is_started().await?; + let get_info_res = self.get_info().await?; let fees_sat; let receiver_amount_sat; let payment_destination; @@ -728,12 +749,16 @@ impl LiquidSdk { InputType::LiquidAddress { address: mut liquid_address_data, } => { - let amount_sat = match (liquid_address_data.amount_sat, req.amount_sat) { + let amount = match (liquid_address_data.amount_sat, req.amount.clone()) { (None, None) => { - return Err(PaymentError::AmountMissing { err: "`amount_sat` must be present when paying to a `SendDestination::LiquidAddress`".to_string() }); + return Err(PaymentError::AmountMissing { + err: "Amount must be set when paying to a Liquid address".to_string(), + }); } - (Some(bip21_amount_sat), None) => bip21_amount_sat, - (_, Some(request_amount_sat)) => request_amount_sat, + (Some(bip21_amount_sat), None) => PayAmount::Receiver { + amount_sat: bip21_amount_sat, + }, + (_, Some(amount)) => amount, }; ensure_sdk!( @@ -747,10 +772,32 @@ impl LiquidSdk { } ); - receiver_amount_sat = amount_sat; - fees_sat = self - .estimate_onchain_tx_fee(receiver_amount_sat, &liquid_address_data.address) - .await?; + (receiver_amount_sat, fees_sat) = match amount { + PayAmount::Drain => { + ensure_sdk!( + get_info_res.pending_receive_sat == 0 + && get_info_res.pending_send_sat == 0, + PaymentError::Generic { + err: "Cannot drain while there are pending payments".to_string(), + } + ); + let drain_fees_sat = self + .estimate_drain_tx_fee(None, Some(&liquid_address_data.address)) + .await?; + let drain_amount_sat = get_info_res.balance_sat - drain_fees_sat; + info!("Drain amount: {drain_amount_sat} sat"); + (drain_amount_sat, drain_fees_sat) + } + PayAmount::Receiver { amount_sat } => { + let fees_sat = self + .estimate_onchain_tx_or_drain_tx_fee( + amount_sat, + &liquid_address_data.address, + ) + .await?; + (amount_sat, fees_sat) + } + }; liquid_address_data.amount_sat = Some(receiver_amount_sat); payment_destination = SendDestination::LiquidAddress { @@ -765,10 +812,12 @@ impl LiquidSdk { err: "Expected invoice with an amount".to_string(), })? / 1000; - if let Some(amount_sat) = req.amount_sat { + if let Some(PayAmount::Receiver { amount_sat }) = req.amount { ensure_sdk!( receiver_amount_sat == amount_sat, - PaymentError::Generic { err: "Amount in the payment request is not the same as the one in the invoice".to_string() } + PaymentError::Generic { + err: "Receiver amount and invoice amount do not match".to_string() + } ); } @@ -776,13 +825,14 @@ impl LiquidSdk { fees_sat = match self.swapper.check_for_mrh(&invoice.bolt11)? { Some((lbtc_address, _)) => { - self.estimate_onchain_tx_fee(receiver_amount_sat, &lbtc_address) + self.estimate_onchain_tx_or_drain_tx_fee(receiver_amount_sat, &lbtc_address) .await? } None => { let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat); + let user_lockup_amount_sat = receiver_amount_sat + boltz_fees_total; let lockup_fees_sat = self - .estimate_lockup_tx_fee_send(receiver_amount_sat + boltz_fees_total) + .estimate_lockup_tx_or_drain_tx_fee(user_lockup_amount_sat) .await?; boltz_fees_total + lockup_fees_sat } @@ -798,7 +848,7 @@ impl LiquidSdk { let payer_amount_sat = receiver_amount_sat + fees_sat; ensure_sdk!( - payer_amount_sat <= self.get_info().await?.balance_sat, + payer_amount_sat <= get_info_res.balance_sat, PaymentError::InsufficientFunds ); @@ -923,10 +973,8 @@ impl LiquidSdk { ) -> Result { let tx = self .onchain_wallet - .build_tx( - self.config - .lowball_fee_rate_msat_per_vbyte() - .map(|v| v as f32), + .build_tx_or_drain_tx( + self.config.lowball_fee_rate_msat_per_vbyte(), &address_data.address, receiver_amount_sat, ) @@ -994,8 +1042,9 @@ impl LiquidSdk { let lbtc_pair = self.validate_submarine_pairs(receiver_amount_sat)?; let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat); + let user_lockup_amount_sat = receiver_amount_sat + boltz_fees_total; let lockup_tx_fees_sat = self - .estimate_lockup_tx_fee_send(receiver_amount_sat + boltz_fees_total) + .estimate_lockup_tx_or_drain_tx_fee(user_lockup_amount_sat) .await?; ensure_sdk!( fees_sat == boltz_fees_total + lockup_tx_fees_sat, @@ -1149,8 +1198,8 @@ impl LiquidSdk { /// # Arguments /// /// * `req` - the [PreparePayOnchainRequest] containing: - /// * `amount` - which can be of two types: [PayOnchainAmount::Drain], which uses all funds, - /// and [PayOnchainAmount::Receiver], which sets the amount the receiver should receive + /// * `amount` - which can be of two types: [PayAmount::Drain], which uses all funds, + /// and [PayAmount::Receiver], which sets the amount the receiver should receive /// * `fee_rate_sat_per_vbyte` - the optional fee rate of the Bitcoin claim transaction. Defaults to the swapper estimated claim fee pub async fn prepare_pay_onchain( &self, @@ -1158,7 +1207,7 @@ impl LiquidSdk { ) -> Result { self.ensure_is_started().await?; - let balance_sat = self.get_info().await?.balance_sat; + let get_info_res = self.get_info().await?; let pair = self.get_chain_pair(Direction::Outgoing)?; let claim_fees_sat = match req.fee_rate_sat_per_vbyte { Some(sat_per_vbyte) => ESTIMATED_BTC_CLAIM_TX_VSIZE * sat_per_vbyte as u64, @@ -1168,7 +1217,7 @@ impl LiquidSdk { info!("Preparing for onchain payment of kind: {:?}", req.amount); let (payer_amount_sat, receiver_amount_sat, total_fees_sat) = match req.amount { - PayOnchainAmount::Receiver { amount_sat } => { + PayAmount::Receiver { amount_sat } => { let receiver_amount_sat = amount_sat; let user_lockup_amount_sat_without_service_fee = @@ -1182,9 +1231,7 @@ impl LiquidSdk { .ceil() as u64; self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?; - let lockup_fees_sat = self - .estimate_lockup_tx_fee_chain_send(user_lockup_amount_sat) - .await?; + let lockup_fees_sat = self.estimate_lockup_tx_fee(user_lockup_amount_sat).await?; let boltz_fees_sat = user_lockup_amount_sat - user_lockup_amount_sat_without_service_fee; @@ -1194,9 +1241,15 @@ impl LiquidSdk { (payer_amount_sat, receiver_amount_sat, total_fees_sat) } - PayOnchainAmount::Drain => { - let payer_amount_sat = balance_sat; - let lockup_fees_sat = self.estimate_drain_tx_fee().await?; + PayAmount::Drain => { + ensure_sdk!( + get_info_res.pending_receive_sat == 0 && get_info_res.pending_send_sat == 0, + PaymentError::Generic { + err: "Cannot drain while there are pending payments".to_string(), + } + ); + let payer_amount_sat = get_info_res.balance_sat; + let lockup_fees_sat = self.estimate_drain_tx_fee(None, None).await?; let user_lockup_amount_sat = payer_amount_sat - lockup_fees_sat; self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?; @@ -1217,7 +1270,7 @@ impl LiquidSdk { }; ensure_sdk!( - payer_amount_sat <= balance_sat, + payer_amount_sat <= get_info_res.balance_sat, PaymentError::InsufficientFunds ); @@ -1269,11 +1322,8 @@ impl LiquidSdk { let payer_amount_sat = req.prepare_response.total_fees_sat + receiver_amount_sat; let lockup_fees_sat = match payer_amount_sat == balance_sat { - true => self.estimate_drain_tx_fee().await?, - false => { - self.estimate_lockup_tx_fee_chain_send(user_lockup_amount_sat) - .await? - } + true => self.estimate_drain_tx_fee(None, None).await?, + false => self.estimate_lockup_tx_fee(user_lockup_amount_sat).await?, }; ensure_sdk!( @@ -2247,7 +2297,7 @@ impl LiquidSdk { let prepare_response = self .prepare_send_payment(&PrepareSendRequest { destination: data.pr.clone(), - amount_sat: None, + amount: None, }) .await .map_err(|e| LnUrlPayError::Generic { err: e.to_string() })?; diff --git a/lib/core/src/send_swap.rs b/lib/core/src/send_swap.rs index c983c51e0..f152ca384 100644 --- a/lib/core/src/send_swap.rs +++ b/lib/core/src/send_swap.rs @@ -190,10 +190,8 @@ impl SendSwapHandler { let lockup_tx = self .onchain_wallet - .build_tx( - self.config - .lowball_fee_rate_msat_per_vbyte() - .map(|v| v as f32), + .build_tx_or_drain_tx( + self.config.lowball_fee_rate_msat_per_vbyte(), &create_response.address, create_response.expected_amount, ) diff --git a/lib/core/src/test_utils/wallet.rs b/lib/core/src/test_utils/wallet.rs index e5c277e64..cd7a6c254 100644 --- a/lib/core/src/test_utils/wallet.rs +++ b/lib/core/src/test_utils/wallet.rs @@ -53,6 +53,15 @@ impl OnchainWallet for MockWallet { Ok(TEST_LIQUID_TX.clone()) } + async fn build_tx_or_drain_tx( + &self, + _fee_rate_sats_per_kvb: Option, + _recipient_address: &str, + _amount_sat: u64, + ) -> Result { + Ok(TEST_LIQUID_TX.clone()) + } + async fn next_unused_address(&self) -> Result { Ok(TEST_P2TR_ADDR.clone()) } diff --git a/lib/core/src/wallet.rs b/lib/core/src/wallet.rs index 82e9632f1..55263c542 100644 --- a/lib/core/src/wallet.rs +++ b/lib/core/src/wallet.rs @@ -4,7 +4,7 @@ use std::{str::FromStr, sync::Arc}; use anyhow::{anyhow, Result}; use async_trait::async_trait; use boltz_client::ElementsAddress; -use log::debug; +use log::{debug, warn}; use lwk_common::Signer as LwkSigner; use lwk_common::{singlesig_desc, Singlesig}; use lwk_wollet::{ @@ -56,6 +56,16 @@ pub trait OnchainWallet: Send + Sync { enforce_amount_sat: Option, ) -> Result; + /// Build a transaction to send funds to a recipient. If building a transaction + /// results in an InsufficientFunds error, attempt to build a drain transaction + /// validating that the `amount_sat` matches the drain output. + async fn build_tx_or_drain_tx( + &self, + fee_rate_sats_per_kvb: Option, + recipient_address: &str, + amount_sat: u64, + ) -> Result; + /// Get the next unused address in the wallet async fn next_unused_address(&self) -> Result; @@ -209,6 +219,26 @@ impl OnchainWallet for LiquidOnchainWallet { Ok(lwk_wollet.finalize(&mut pset)?) } + async fn build_tx_or_drain_tx( + &self, + fee_rate_sats_per_kvb: Option, + recipient_address: &str, + amount_sat: u64, + ) -> Result { + match self + .build_tx(fee_rate_sats_per_kvb, recipient_address, amount_sat) + .await + { + Ok(tx) => Ok(tx), + Err(PaymentError::InsufficientFunds) => { + warn!("Cannot build tx due to insufficient funds, attempting to build drain tx"); + self.build_drain_tx(fee_rate_sats_per_kvb, recipient_address, Some(amount_sat)) + .await + } + Err(e) => Err(e), + } + } + /// Get the next unused address in the wallet async fn next_unused_address(&self) -> Result { let tip = self.tip().await.height(); diff --git a/packages/dart/lib/src/frb_generated.dart b/packages/dart/lib/src/frb_generated.dart index a382c9dbb..27733df60 100644 --- a/packages/dart/lib/src/frb_generated.dart +++ b/packages/dart/lib/src/frb_generated.dart @@ -1483,6 +1483,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return dco_decode_message_success_action_data(raw); } + @protected + PayAmount dco_decode_box_autoadd_pay_amount(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dco_decode_pay_amount(raw); + } + @protected PayOnchainRequest dco_decode_box_autoadd_pay_onchain_request(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -2305,6 +2311,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw == null ? null : dco_decode_box_autoadd_list_payment_details(raw); } + @protected + PayAmount? dco_decode_opt_box_autoadd_pay_amount(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_box_autoadd_pay_amount(raw); + } + @protected Payment? dco_decode_opt_box_autoadd_payment(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -2348,15 +2360,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - PayOnchainAmount dco_decode_pay_onchain_amount(dynamic raw) { + PayAmount dco_decode_pay_amount(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs switch (raw[0]) { case 0: - return PayOnchainAmount_Receiver( + return PayAmount_Receiver( amountSat: dco_decode_u_64(raw[1]), ); case 1: - return PayOnchainAmount_Drain(); + return PayAmount_Drain(); default: throw Exception("unreachable"); } @@ -2565,7 +2577,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { final arr = raw as List; if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); return PreparePayOnchainRequest( - amount: dco_decode_pay_onchain_amount(arr[0]), + amount: dco_decode_pay_amount(arr[0]), feeRateSatPerVbyte: dco_decode_opt_box_autoadd_u_32(arr[1]), ); } @@ -2636,7 +2648,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); return PrepareSendRequest( destination: dco_decode_String(arr[0]), - amountSat: dco_decode_opt_box_autoadd_u_64(arr[1]), + amount: dco_decode_opt_box_autoadd_pay_amount(arr[1]), ); } @@ -3264,6 +3276,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return (sse_decode_message_success_action_data(deserializer)); } + @protected + PayAmount sse_decode_box_autoadd_pay_amount(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return (sse_decode_pay_amount(deserializer)); + } + @protected PayOnchainRequest sse_decode_box_autoadd_pay_onchain_request(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -4121,6 +4139,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + PayAmount? sse_decode_opt_box_autoadd_pay_amount(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return (sse_decode_box_autoadd_pay_amount(deserializer)); + } else { + return null; + } + } + @protected Payment? sse_decode_opt_box_autoadd_payment(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -4199,16 +4228,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - PayOnchainAmount sse_decode_pay_onchain_amount(SseDeserializer deserializer) { + PayAmount sse_decode_pay_amount(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs var tag_ = sse_decode_i_32(deserializer); switch (tag_) { case 0: var var_amountSat = sse_decode_u_64(deserializer); - return PayOnchainAmount_Receiver(amountSat: var_amountSat); + return PayAmount_Receiver(amountSat: var_amountSat); case 1: - return PayOnchainAmount_Drain(); + return PayAmount_Drain(); default: throw UnimplementedError(''); } @@ -4414,7 +4443,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @protected PreparePayOnchainRequest sse_decode_prepare_pay_onchain_request(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs - var var_amount = sse_decode_pay_onchain_amount(deserializer); + var var_amount = sse_decode_pay_amount(deserializer); var var_feeRateSatPerVbyte = sse_decode_opt_box_autoadd_u_32(deserializer); return PreparePayOnchainRequest(amount: var_amount, feeRateSatPerVbyte: var_feeRateSatPerVbyte); } @@ -4474,8 +4503,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { PrepareSendRequest sse_decode_prepare_send_request(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs var var_destination = sse_decode_String(deserializer); - var var_amountSat = sse_decode_opt_box_autoadd_u_64(deserializer); - return PrepareSendRequest(destination: var_destination, amountSat: var_amountSat); + var var_amount = sse_decode_opt_box_autoadd_pay_amount(deserializer); + return PrepareSendRequest(destination: var_destination, amount: var_amount); } @protected @@ -5162,6 +5191,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_message_success_action_data(self, serializer); } + @protected + void sse_encode_box_autoadd_pay_amount(PayAmount self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_pay_amount(self, serializer); + } + @protected void sse_encode_box_autoadd_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -5887,6 +5922,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + void sse_encode_opt_box_autoadd_pay_amount(PayAmount? self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_box_autoadd_pay_amount(self, serializer); + } + } + @protected void sse_encode_opt_box_autoadd_payment(Payment? self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -5959,13 +6004,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - void sse_encode_pay_onchain_amount(PayOnchainAmount self, SseSerializer serializer) { + void sse_encode_pay_amount(PayAmount self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs switch (self) { - case PayOnchainAmount_Receiver(amountSat: final amountSat): + case PayAmount_Receiver(amountSat: final amountSat): sse_encode_i_32(0, serializer); sse_encode_u_64(amountSat, serializer); - case PayOnchainAmount_Drain(): + case PayAmount_Drain(): sse_encode_i_32(1, serializer); default: throw UnimplementedError(''); @@ -6148,7 +6193,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @protected void sse_encode_prepare_pay_onchain_request(PreparePayOnchainRequest self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_pay_onchain_amount(self.amount, serializer); + sse_encode_pay_amount(self.amount, serializer); sse_encode_opt_box_autoadd_u_32(self.feeRateSatPerVbyte, serializer); } @@ -6195,7 +6240,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { void sse_encode_prepare_send_request(PrepareSendRequest self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_String(self.destination, serializer); - sse_encode_opt_box_autoadd_u_64(self.amountSat, serializer); + sse_encode_opt_box_autoadd_pay_amount(self.amount, serializer); } @protected diff --git a/packages/dart/lib/src/frb_generated.io.dart b/packages/dart/lib/src/frb_generated.io.dart index d5f2bf4b6..41fc0c08d 100644 --- a/packages/dart/lib/src/frb_generated.io.dart +++ b/packages/dart/lib/src/frb_generated.io.dart @@ -149,6 +149,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected MessageSuccessActionData dco_decode_box_autoadd_message_success_action_data(dynamic raw); + @protected + PayAmount dco_decode_box_autoadd_pay_amount(dynamic raw); + @protected PayOnchainRequest dco_decode_box_autoadd_pay_onchain_request(dynamic raw); @@ -377,6 +380,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected ListPaymentDetails? dco_decode_opt_box_autoadd_list_payment_details(dynamic raw); + @protected + PayAmount? dco_decode_opt_box_autoadd_pay_amount(dynamic raw); + @protected Payment? dco_decode_opt_box_autoadd_payment(dynamic raw); @@ -399,7 +405,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { List? dco_decode_opt_list_payment_type(dynamic raw); @protected - PayOnchainAmount dco_decode_pay_onchain_amount(dynamic raw); + PayAmount dco_decode_pay_amount(dynamic raw); @protected PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw); @@ -666,6 +672,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected MessageSuccessActionData sse_decode_box_autoadd_message_success_action_data(SseDeserializer deserializer); + @protected + PayAmount sse_decode_box_autoadd_pay_amount(SseDeserializer deserializer); + @protected PayOnchainRequest sse_decode_box_autoadd_pay_onchain_request(SseDeserializer deserializer); @@ -894,6 +903,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected ListPaymentDetails? sse_decode_opt_box_autoadd_list_payment_details(SseDeserializer deserializer); + @protected + PayAmount? sse_decode_opt_box_autoadd_pay_amount(SseDeserializer deserializer); + @protected Payment? sse_decode_opt_box_autoadd_payment(SseDeserializer deserializer); @@ -916,7 +928,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { List? sse_decode_opt_list_payment_type(SseDeserializer deserializer); @protected - PayOnchainAmount sse_decode_pay_onchain_amount(SseDeserializer deserializer); + PayAmount sse_decode_pay_amount(SseDeserializer deserializer); @protected PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer); @@ -1313,6 +1325,14 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { return ptr; } + @protected + ffi.Pointer cst_encode_box_autoadd_pay_amount(PayAmount raw) { + // Codec=Cst (C-struct based), see doc to use other codecs + final ptr = wire.cst_new_box_autoadd_pay_amount(); + cst_api_fill_to_wire_pay_amount(raw, ptr.ref); + return ptr; + } + @protected ffi.Pointer cst_encode_box_autoadd_pay_onchain_request( PayOnchainRequest raw) { @@ -1610,6 +1630,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { return raw == null ? ffi.nullptr : cst_encode_box_autoadd_list_payment_details(raw); } + @protected + ffi.Pointer cst_encode_opt_box_autoadd_pay_amount(PayAmount? raw) { + // Codec=Cst (C-struct based), see doc to use other codecs + return raw == null ? ffi.nullptr : cst_encode_box_autoadd_pay_amount(raw); + } + @protected ffi.Pointer cst_encode_opt_box_autoadd_payment(Payment? raw) { // Codec=Cst (C-struct based), see doc to use other codecs @@ -1862,6 +1888,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { cst_api_fill_to_wire_message_success_action_data(apiObj, wireObj.ref); } + @protected + void cst_api_fill_to_wire_box_autoadd_pay_amount( + PayAmount apiObj, ffi.Pointer wireObj) { + cst_api_fill_to_wire_pay_amount(apiObj, wireObj.ref); + } + @protected void cst_api_fill_to_wire_box_autoadd_pay_onchain_request( PayOnchainRequest apiObj, ffi.Pointer wireObj) { @@ -2472,14 +2504,14 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { } @protected - void cst_api_fill_to_wire_pay_onchain_amount(PayOnchainAmount apiObj, wire_cst_pay_onchain_amount wireObj) { - if (apiObj is PayOnchainAmount_Receiver) { + void cst_api_fill_to_wire_pay_amount(PayAmount apiObj, wire_cst_pay_amount wireObj) { + if (apiObj is PayAmount_Receiver) { var pre_amount_sat = cst_encode_u_64(apiObj.amountSat); wireObj.tag = 0; wireObj.kind.Receiver.amount_sat = pre_amount_sat; return; } - if (apiObj is PayOnchainAmount_Drain) { + if (apiObj is PayAmount_Drain) { wireObj.tag = 1; return; } @@ -2691,7 +2723,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void cst_api_fill_to_wire_prepare_pay_onchain_request( PreparePayOnchainRequest apiObj, wire_cst_prepare_pay_onchain_request wireObj) { - cst_api_fill_to_wire_pay_onchain_amount(apiObj.amount, wireObj.amount); + cst_api_fill_to_wire_pay_amount(apiObj.amount, wireObj.amount); wireObj.fee_rate_sat_per_vbyte = cst_encode_opt_box_autoadd_u_32(apiObj.feeRateSatPerVbyte); } @@ -2738,7 +2770,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void cst_api_fill_to_wire_prepare_send_request( PrepareSendRequest apiObj, wire_cst_prepare_send_request wireObj) { wireObj.destination = cst_encode_String(apiObj.destination); - wireObj.amount_sat = cst_encode_opt_box_autoadd_u_64(apiObj.amountSat); + wireObj.amount = cst_encode_opt_box_autoadd_pay_amount(apiObj.amount); } @protected @@ -3166,6 +3198,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_box_autoadd_message_success_action_data( MessageSuccessActionData self, SseSerializer serializer); + @protected + void sse_encode_box_autoadd_pay_amount(PayAmount self, SseSerializer serializer); + @protected void sse_encode_box_autoadd_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer); @@ -3399,6 +3434,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_opt_box_autoadd_list_payment_details(ListPaymentDetails? self, SseSerializer serializer); + @protected + void sse_encode_opt_box_autoadd_pay_amount(PayAmount? self, SseSerializer serializer); + @protected void sse_encode_opt_box_autoadd_payment(Payment? self, SseSerializer serializer); @@ -3422,7 +3460,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_opt_list_payment_type(List? self, SseSerializer serializer); @protected - void sse_encode_pay_onchain_amount(PayOnchainAmount self, SseSerializer serializer); + void sse_encode_pay_amount(PayAmount self, SseSerializer serializer); @protected void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer); @@ -4629,6 +4667,16 @@ class RustLibWire implements BaseWire { _cst_new_box_autoadd_message_success_action_dataPtr .asFunction Function()>(); + ffi.Pointer cst_new_box_autoadd_pay_amount() { + return _cst_new_box_autoadd_pay_amount(); + } + + late final _cst_new_box_autoadd_pay_amountPtr = + _lookup Function()>>( + 'frbgen_breez_liquid_cst_new_box_autoadd_pay_amount'); + late final _cst_new_box_autoadd_pay_amount = + _cst_new_box_autoadd_pay_amountPtr.asFunction Function()>(); + ffi.Pointer cst_new_box_autoadd_pay_onchain_request() { return _cst_new_box_autoadd_pay_onchain_request(); } @@ -5347,24 +5395,24 @@ final class wire_cst_prepare_ln_url_pay_request extends ffi.Struct { external ffi.Pointer validate_success_action_url; } -final class wire_cst_PayOnchainAmount_Receiver extends ffi.Struct { +final class wire_cst_PayAmount_Receiver extends ffi.Struct { @ffi.Uint64() external int amount_sat; } -final class PayOnchainAmountKind extends ffi.Union { - external wire_cst_PayOnchainAmount_Receiver Receiver; +final class PayAmountKind extends ffi.Union { + external wire_cst_PayAmount_Receiver Receiver; } -final class wire_cst_pay_onchain_amount extends ffi.Struct { +final class wire_cst_pay_amount extends ffi.Struct { @ffi.Int32() external int tag; - external PayOnchainAmountKind kind; + external PayAmountKind kind; } final class wire_cst_prepare_pay_onchain_request extends ffi.Struct { - external wire_cst_pay_onchain_amount amount; + external wire_cst_pay_amount amount; external ffi.Pointer fee_rate_sat_per_vbyte; } @@ -5388,7 +5436,7 @@ final class wire_cst_prepare_refund_request extends ffi.Struct { final class wire_cst_prepare_send_request extends ffi.Struct { external ffi.Pointer destination; - external ffi.Pointer amount_sat; + external ffi.Pointer amount; } final class wire_cst_prepare_receive_response extends ffi.Struct { diff --git a/packages/dart/lib/src/model.dart b/packages/dart/lib/src/model.dart index bc2ea5cb8..04ad60e84 100644 --- a/packages/dart/lib/src/model.dart +++ b/packages/dart/lib/src/model.dart @@ -476,16 +476,16 @@ class OnchainPaymentLimitsResponse { } @freezed -sealed class PayOnchainAmount with _$PayOnchainAmount { - const PayOnchainAmount._(); +sealed class PayAmount with _$PayAmount { + const PayAmount._(); /// The amount in satoshi that will be received - const factory PayOnchainAmount.receiver({ + const factory PayAmount.receiver({ required BigInt amountSat, - }) = PayOnchainAmount_Receiver; + }) = PayAmount_Receiver; /// Indicates that all available funds should be sent - const factory PayOnchainAmount.drain() = PayOnchainAmount_Drain; + const factory PayAmount.drain() = PayAmount_Drain; } /// An argument when calling [crate::sdk::LiquidSdk::pay_onchain]. @@ -849,7 +849,7 @@ class PrepareLnUrlPayResponse { /// An argument when calling [crate::sdk::LiquidSdk::prepare_pay_onchain]. class PreparePayOnchainRequest { - final PayOnchainAmount amount; + final PayAmount amount; /// The optional fee rate of the Bitcoin claim transaction in sat/vB. Defaults to the swapper estimated claim fee. final int? feeRateSatPerVbyte; @@ -1005,16 +1005,16 @@ class PrepareSendRequest { final String destination; /// Should only be set when paying directly onchain or to a BIP21 URI - /// where no amount is specified - final BigInt? amountSat; + /// where no amount is specified, or when the caller wishes to drain + final PayAmount? amount; const PrepareSendRequest({ required this.destination, - this.amountSat, + this.amount, }); @override - int get hashCode => destination.hashCode ^ amountSat.hashCode; + int get hashCode => destination.hashCode ^ amount.hashCode; @override bool operator ==(Object other) => @@ -1022,7 +1022,7 @@ class PrepareSendRequest { other is PrepareSendRequest && runtimeType == other.runtimeType && destination == other.destination && - amountSat == other.amountSat; + amount == other.amount; } /// Returned when calling [crate::sdk::LiquidSdk::prepare_send_payment]. diff --git a/packages/dart/lib/src/model.freezed.dart b/packages/dart/lib/src/model.freezed.dart index 067875218..37d19aaf8 100644 --- a/packages/dart/lib/src/model.freezed.dart +++ b/packages/dart/lib/src/model.freezed.dart @@ -594,53 +594,52 @@ abstract class LnUrlPayResult_PayError extends LnUrlPayResult { } /// @nodoc -mixin _$PayOnchainAmount {} +mixin _$PayAmount {} /// @nodoc -abstract class $PayOnchainAmountCopyWith<$Res> { - factory $PayOnchainAmountCopyWith(PayOnchainAmount value, $Res Function(PayOnchainAmount) then) = - _$PayOnchainAmountCopyWithImpl<$Res, PayOnchainAmount>; +abstract class $PayAmountCopyWith<$Res> { + factory $PayAmountCopyWith(PayAmount value, $Res Function(PayAmount) then) = + _$PayAmountCopyWithImpl<$Res, PayAmount>; } /// @nodoc -class _$PayOnchainAmountCopyWithImpl<$Res, $Val extends PayOnchainAmount> - implements $PayOnchainAmountCopyWith<$Res> { - _$PayOnchainAmountCopyWithImpl(this._value, this._then); +class _$PayAmountCopyWithImpl<$Res, $Val extends PayAmount> implements $PayAmountCopyWith<$Res> { + _$PayAmountCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of PayOnchainAmount + /// Create a copy of PayAmount /// with the given fields replaced by the non-null parameter values. } /// @nodoc -abstract class _$$PayOnchainAmount_ReceiverImplCopyWith<$Res> { - factory _$$PayOnchainAmount_ReceiverImplCopyWith( - _$PayOnchainAmount_ReceiverImpl value, $Res Function(_$PayOnchainAmount_ReceiverImpl) then) = - __$$PayOnchainAmount_ReceiverImplCopyWithImpl<$Res>; +abstract class _$$PayAmount_ReceiverImplCopyWith<$Res> { + factory _$$PayAmount_ReceiverImplCopyWith( + _$PayAmount_ReceiverImpl value, $Res Function(_$PayAmount_ReceiverImpl) then) = + __$$PayAmount_ReceiverImplCopyWithImpl<$Res>; @useResult $Res call({BigInt amountSat}); } /// @nodoc -class __$$PayOnchainAmount_ReceiverImplCopyWithImpl<$Res> - extends _$PayOnchainAmountCopyWithImpl<$Res, _$PayOnchainAmount_ReceiverImpl> - implements _$$PayOnchainAmount_ReceiverImplCopyWith<$Res> { - __$$PayOnchainAmount_ReceiverImplCopyWithImpl( - _$PayOnchainAmount_ReceiverImpl _value, $Res Function(_$PayOnchainAmount_ReceiverImpl) _then) +class __$$PayAmount_ReceiverImplCopyWithImpl<$Res> + extends _$PayAmountCopyWithImpl<$Res, _$PayAmount_ReceiverImpl> + implements _$$PayAmount_ReceiverImplCopyWith<$Res> { + __$$PayAmount_ReceiverImplCopyWithImpl( + _$PayAmount_ReceiverImpl _value, $Res Function(_$PayAmount_ReceiverImpl) _then) : super(_value, _then); - /// Create a copy of PayOnchainAmount + /// Create a copy of PayAmount /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ Object? amountSat = null, }) { - return _then(_$PayOnchainAmount_ReceiverImpl( + return _then(_$PayAmount_ReceiverImpl( amountSat: null == amountSat ? _value.amountSat : amountSat // ignore: cast_nullable_to_non_nullable @@ -651,93 +650,90 @@ class __$$PayOnchainAmount_ReceiverImplCopyWithImpl<$Res> /// @nodoc -class _$PayOnchainAmount_ReceiverImpl extends PayOnchainAmount_Receiver { - const _$PayOnchainAmount_ReceiverImpl({required this.amountSat}) : super._(); +class _$PayAmount_ReceiverImpl extends PayAmount_Receiver { + const _$PayAmount_ReceiverImpl({required this.amountSat}) : super._(); @override final BigInt amountSat; @override String toString() { - return 'PayOnchainAmount.receiver(amountSat: $amountSat)'; + return 'PayAmount.receiver(amountSat: $amountSat)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$PayOnchainAmount_ReceiverImpl && + other is _$PayAmount_ReceiverImpl && (identical(other.amountSat, amountSat) || other.amountSat == amountSat)); } @override int get hashCode => Object.hash(runtimeType, amountSat); - /// Create a copy of PayOnchainAmount + /// Create a copy of PayAmount /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$PayOnchainAmount_ReceiverImplCopyWith<_$PayOnchainAmount_ReceiverImpl> get copyWith => - __$$PayOnchainAmount_ReceiverImplCopyWithImpl<_$PayOnchainAmount_ReceiverImpl>(this, _$identity); + _$$PayAmount_ReceiverImplCopyWith<_$PayAmount_ReceiverImpl> get copyWith => + __$$PayAmount_ReceiverImplCopyWithImpl<_$PayAmount_ReceiverImpl>(this, _$identity); } -abstract class PayOnchainAmount_Receiver extends PayOnchainAmount { - const factory PayOnchainAmount_Receiver({required final BigInt amountSat}) = - _$PayOnchainAmount_ReceiverImpl; - const PayOnchainAmount_Receiver._() : super._(); +abstract class PayAmount_Receiver extends PayAmount { + const factory PayAmount_Receiver({required final BigInt amountSat}) = _$PayAmount_ReceiverImpl; + const PayAmount_Receiver._() : super._(); BigInt get amountSat; - /// Create a copy of PayOnchainAmount + /// Create a copy of PayAmount /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - _$$PayOnchainAmount_ReceiverImplCopyWith<_$PayOnchainAmount_ReceiverImpl> get copyWith => + _$$PayAmount_ReceiverImplCopyWith<_$PayAmount_ReceiverImpl> get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class _$$PayOnchainAmount_DrainImplCopyWith<$Res> { - factory _$$PayOnchainAmount_DrainImplCopyWith( - _$PayOnchainAmount_DrainImpl value, $Res Function(_$PayOnchainAmount_DrainImpl) then) = - __$$PayOnchainAmount_DrainImplCopyWithImpl<$Res>; +abstract class _$$PayAmount_DrainImplCopyWith<$Res> { + factory _$$PayAmount_DrainImplCopyWith( + _$PayAmount_DrainImpl value, $Res Function(_$PayAmount_DrainImpl) then) = + __$$PayAmount_DrainImplCopyWithImpl<$Res>; } /// @nodoc -class __$$PayOnchainAmount_DrainImplCopyWithImpl<$Res> - extends _$PayOnchainAmountCopyWithImpl<$Res, _$PayOnchainAmount_DrainImpl> - implements _$$PayOnchainAmount_DrainImplCopyWith<$Res> { - __$$PayOnchainAmount_DrainImplCopyWithImpl( - _$PayOnchainAmount_DrainImpl _value, $Res Function(_$PayOnchainAmount_DrainImpl) _then) +class __$$PayAmount_DrainImplCopyWithImpl<$Res> extends _$PayAmountCopyWithImpl<$Res, _$PayAmount_DrainImpl> + implements _$$PayAmount_DrainImplCopyWith<$Res> { + __$$PayAmount_DrainImplCopyWithImpl( + _$PayAmount_DrainImpl _value, $Res Function(_$PayAmount_DrainImpl) _then) : super(_value, _then); - /// Create a copy of PayOnchainAmount + /// Create a copy of PayAmount /// with the given fields replaced by the non-null parameter values. } /// @nodoc -class _$PayOnchainAmount_DrainImpl extends PayOnchainAmount_Drain { - const _$PayOnchainAmount_DrainImpl() : super._(); +class _$PayAmount_DrainImpl extends PayAmount_Drain { + const _$PayAmount_DrainImpl() : super._(); @override String toString() { - return 'PayOnchainAmount.drain()'; + return 'PayAmount.drain()'; } @override bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is _$PayOnchainAmount_DrainImpl); + return identical(this, other) || (other.runtimeType == runtimeType && other is _$PayAmount_DrainImpl); } @override int get hashCode => runtimeType.hashCode; } -abstract class PayOnchainAmount_Drain extends PayOnchainAmount { - const factory PayOnchainAmount_Drain() = _$PayOnchainAmount_DrainImpl; - const PayOnchainAmount_Drain._() : super._(); +abstract class PayAmount_Drain extends PayAmount { + const factory PayAmount_Drain() = _$PayAmount_DrainImpl; + const PayAmount_Drain._() : super._(); } /// @nodoc diff --git a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart index 46b986ea1..e623c13ac 100644 --- a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart +++ b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart @@ -1116,6 +1116,17 @@ class FlutterBreezLiquidBindings { _frbgen_breez_liquid_cst_new_box_autoadd_message_success_action_dataPtr .asFunction Function()>(); + ffi.Pointer frbgen_breez_liquid_cst_new_box_autoadd_pay_amount() { + return _frbgen_breez_liquid_cst_new_box_autoadd_pay_amount(); + } + + late final _frbgen_breez_liquid_cst_new_box_autoadd_pay_amountPtr = + _lookup Function()>>( + 'frbgen_breez_liquid_cst_new_box_autoadd_pay_amount'); + late final _frbgen_breez_liquid_cst_new_box_autoadd_pay_amount = + _frbgen_breez_liquid_cst_new_box_autoadd_pay_amountPtr + .asFunction Function()>(); + ffi.Pointer frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request() { return _frbgen_breez_liquid_cst_new_box_autoadd_pay_onchain_request(); } @@ -4143,24 +4154,24 @@ final class wire_cst_prepare_ln_url_pay_request extends ffi.Struct { external ffi.Pointer validate_success_action_url; } -final class wire_cst_PayOnchainAmount_Receiver extends ffi.Struct { +final class wire_cst_PayAmount_Receiver extends ffi.Struct { @ffi.Uint64() external int amount_sat; } -final class PayOnchainAmountKind extends ffi.Union { - external wire_cst_PayOnchainAmount_Receiver Receiver; +final class PayAmountKind extends ffi.Union { + external wire_cst_PayAmount_Receiver Receiver; } -final class wire_cst_pay_onchain_amount extends ffi.Struct { +final class wire_cst_pay_amount extends ffi.Struct { @ffi.Int32() external int tag; - external PayOnchainAmountKind kind; + external PayAmountKind kind; } final class wire_cst_prepare_pay_onchain_request extends ffi.Struct { - external wire_cst_pay_onchain_amount amount; + external wire_cst_pay_amount amount; external ffi.Pointer fee_rate_sat_per_vbyte; } @@ -4184,7 +4195,7 @@ final class wire_cst_prepare_refund_request extends ffi.Struct { final class wire_cst_prepare_send_request extends ffi.Struct { external ffi.Pointer destination; - external ffi.Pointer amount_sat; + external ffi.Pointer amount; } final class wire_cst_prepare_receive_response extends ffi.Struct { diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt index b9c340314..9759daed3 100644 --- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt +++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt @@ -1487,7 +1487,7 @@ fun asPreparePayOnchainRequest(preparePayOnchainRequest: ReadableMap): PreparePa ) { return null } - val amount = preparePayOnchainRequest.getMap("amount")?.let { asPayOnchainAmount(it) }!! + val amount = preparePayOnchainRequest.getMap("amount")?.let { asPayAmount(it) }!! val feeRateSatPerVbyte = if (hasNonNullKey( preparePayOnchainRequest, @@ -1721,14 +1721,14 @@ fun asPrepareSendRequest(prepareSendRequest: ReadableMap): PrepareSendRequest? { return null } val destination = prepareSendRequest.getString("destination")!! - val amountSat = if (hasNonNullKey(prepareSendRequest, "amountSat")) prepareSendRequest.getDouble("amountSat").toULong() else null - return PrepareSendRequest(destination, amountSat) + val amount = if (hasNonNullKey(prepareSendRequest, "amount")) prepareSendRequest.getMap("amount")?.let { asPayAmount(it) } else null + return PrepareSendRequest(destination, amount) } fun readableMapOf(prepareSendRequest: PrepareSendRequest): ReadableMap = readableMapOf( "destination" to prepareSendRequest.destination, - "amountSat" to prepareSendRequest.amountSat, + "amount" to prepareSendRequest.amount?.let { readableMapOf(it) }, ) fun asPrepareSendRequestList(arr: ReadableArray): List { @@ -2708,38 +2708,38 @@ fun asNetworkList(arr: ReadableArray): List { return list } -fun asPayOnchainAmount(payOnchainAmount: ReadableMap): PayOnchainAmount? { - val type = payOnchainAmount.getString("type") +fun asPayAmount(payAmount: ReadableMap): PayAmount? { + val type = payAmount.getString("type") if (type == "receiver") { - val amountSat = payOnchainAmount.getDouble("amountSat").toULong() - return PayOnchainAmount.Receiver(amountSat) + val amountSat = payAmount.getDouble("amountSat").toULong() + return PayAmount.Receiver(amountSat) } if (type == "drain") { - return PayOnchainAmount.Drain + return PayAmount.Drain } return null } -fun readableMapOf(payOnchainAmount: PayOnchainAmount): ReadableMap? { +fun readableMapOf(payAmount: PayAmount): ReadableMap? { val map = Arguments.createMap() - when (payOnchainAmount) { - is PayOnchainAmount.Receiver -> { + when (payAmount) { + is PayAmount.Receiver -> { pushToMap(map, "type", "receiver") - pushToMap(map, "amountSat", payOnchainAmount.amountSat) + pushToMap(map, "amountSat", payAmount.amountSat) } - is PayOnchainAmount.Drain -> { + is PayAmount.Drain -> { pushToMap(map, "type", "drain") } } return map } -fun asPayOnchainAmountList(arr: ReadableArray): List { - val list = ArrayList() +fun asPayAmountList(arr: ReadableArray): List { + val list = ArrayList() for (value in arr.toList()) { when (value) { - is ReadableMap -> list.add(asPayOnchainAmount(value)!!) + is ReadableMap -> list.add(asPayAmount(value)!!) else -> throw SdkException.Generic(errUnexpectedType(value)) } } diff --git a/packages/react-native/ios/BreezSDKLiquidMapper.swift b/packages/react-native/ios/BreezSDKLiquidMapper.swift index 2efdbb4e7..baaad5850 100644 --- a/packages/react-native/ios/BreezSDKLiquidMapper.swift +++ b/packages/react-native/ios/BreezSDKLiquidMapper.swift @@ -1728,7 +1728,7 @@ enum BreezSDKLiquidMapper { guard let amountTmp = preparePayOnchainRequest["amount"] as? [String: Any?] else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "amount", typeName: "PreparePayOnchainRequest")) } - let amount = try asPayOnchainAmount(payOnchainAmount: amountTmp) + let amount = try asPayAmount(payAmount: amountTmp) var feeRateSatPerVbyte: UInt32? if hasNonNilKey(data: preparePayOnchainRequest, key: "feeRateSatPerVbyte") { @@ -1743,7 +1743,7 @@ enum BreezSDKLiquidMapper { static func dictionaryOf(preparePayOnchainRequest: PreparePayOnchainRequest) -> [String: Any?] { return [ - "amount": dictionaryOf(payOnchainAmount: preparePayOnchainRequest.amount), + "amount": dictionaryOf(payAmount: preparePayOnchainRequest.amount), "feeRateSatPerVbyte": preparePayOnchainRequest.feeRateSatPerVbyte == nil ? nil : preparePayOnchainRequest.feeRateSatPerVbyte, ] } @@ -1976,21 +1976,18 @@ enum BreezSDKLiquidMapper { guard let destination = prepareSendRequest["destination"] as? String else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "destination", typeName: "PrepareSendRequest")) } - var amountSat: UInt64? - if hasNonNilKey(data: prepareSendRequest, key: "amountSat") { - guard let amountSatTmp = prepareSendRequest["amountSat"] as? UInt64 else { - throw SdkError.Generic(message: errUnexpectedValue(fieldName: "amountSat")) - } - amountSat = amountSatTmp + var amount: PayAmount? + if let amountTmp = prepareSendRequest["amount"] as? [String: Any?] { + amount = try asPayAmount(payAmount: amountTmp) } - return PrepareSendRequest(destination: destination, amountSat: amountSat) + return PrepareSendRequest(destination: destination, amount: amount) } static func dictionaryOf(prepareSendRequest: PrepareSendRequest) -> [String: Any?] { return [ "destination": prepareSendRequest.destination, - "amountSat": prepareSendRequest.amountSat == nil ? nil : prepareSendRequest.amountSat, + "amount": prepareSendRequest.amount == nil ? nil : dictionaryOf(payAmount: prepareSendRequest.amount!), ] } @@ -3317,23 +3314,23 @@ enum BreezSDKLiquidMapper { return list } - static func asPayOnchainAmount(payOnchainAmount: [String: Any?]) throws -> PayOnchainAmount { - let type = payOnchainAmount["type"] as! String + static func asPayAmount(payAmount: [String: Any?]) throws -> PayAmount { + let type = payAmount["type"] as! String if type == "receiver" { - guard let _amountSat = payOnchainAmount["amountSat"] as? UInt64 else { - throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "amountSat", typeName: "PayOnchainAmount")) + guard let _amountSat = payAmount["amountSat"] as? UInt64 else { + throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "amountSat", typeName: "PayAmount")) } - return PayOnchainAmount.receiver(amountSat: _amountSat) + return PayAmount.receiver(amountSat: _amountSat) } if type == "drain" { - return PayOnchainAmount.drain + return PayAmount.drain } - throw SdkError.Generic(message: "Unexpected type \(type) for enum PayOnchainAmount") + throw SdkError.Generic(message: "Unexpected type \(type) for enum PayAmount") } - static func dictionaryOf(payOnchainAmount: PayOnchainAmount) -> [String: Any?] { - switch payOnchainAmount { + static func dictionaryOf(payAmount: PayAmount) -> [String: Any?] { + switch payAmount { case let .receiver( amountSat ): @@ -3349,18 +3346,18 @@ enum BreezSDKLiquidMapper { } } - static func arrayOf(payOnchainAmountList: [PayOnchainAmount]) -> [Any] { - return payOnchainAmountList.map { v -> [String: Any?] in return dictionaryOf(payOnchainAmount: v) } + static func arrayOf(payAmountList: [PayAmount]) -> [Any] { + return payAmountList.map { v -> [String: Any?] in return dictionaryOf(payAmount: v) } } - static func asPayOnchainAmountList(arr: [Any]) throws -> [PayOnchainAmount] { - var list = [PayOnchainAmount]() + static func asPayAmountList(arr: [Any]) throws -> [PayAmount] { + var list = [PayAmount]() for value in arr { if let val = value as? [String: Any?] { - var payOnchainAmount = try asPayOnchainAmount(payOnchainAmount: val) - list.append(payOnchainAmount) + var payAmount = try asPayAmount(payAmount: val) + list.append(payAmount) } else { - throw SdkError.Generic(message: errUnexpectedType(typeName: "PayOnchainAmount")) + throw SdkError.Generic(message: errUnexpectedType(typeName: "PayAmount")) } } return list diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index dac70d1d1..5ec413950 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -266,7 +266,7 @@ export interface PrepareLnUrlPayResponse { } export interface PreparePayOnchainRequest { - amount: PayOnchainAmount + amount: PayAmount feeRateSatPerVbyte?: number } @@ -301,7 +301,7 @@ export interface PrepareRefundResponse { export interface PrepareSendRequest { destination: string - amountSat?: number + amount?: PayAmount } export interface PrepareSendResponse { @@ -533,16 +533,16 @@ export enum Network { REGTEST = "regtest" } -export enum PayOnchainAmountVariant { +export enum PayAmountVariant { RECEIVER = "receiver", DRAIN = "drain" } -export type PayOnchainAmount = { - type: PayOnchainAmountVariant.RECEIVER, +export type PayAmount = { + type: PayAmountVariant.RECEIVER, amountSat: number } | { - type: PayOnchainAmountVariant.DRAIN + type: PayAmountVariant.DRAIN } export enum PaymentDetailsVariant {