mirror of
https://github.com/aljazceru/breez-sdk-liquid.git
synced 2025-12-23 17:04:25 +01:00
prepare-pay-onchain: add option for drain (#464)
* prepare-pay-onchain: add option for drain in req * Fix clippy * ChainSwapStateHandler: gracefully handle building both drain and non-drain lockups * Send Chain swap: use standard feerate when estimating lockup tx fee * UDL: move new drain field above the last PreparePayOnchainRequest optional field * UDL: move new drain field optional * prepare-pay-onchain: treat normal payment as drain if receiver amount is high enough If the receiver amount is as high as it would be in case of drain, treat the current prepare-pay-onchain as drain, even if the drain flag is not set. * build_drain_tx: add optional amount validation * Add PayOnchainAmount enum to cover amount types (drain, receiver) * Add ability to find max_receiver_amount_sat for non-drain sends * Revert "Add ability to find max_receiver_amount_sat for non-drain sends" This reverts commit 60ee1c768021810f72bc64a8ada69d35b638185e. * prepare_pay_onchain: treat drain and non-drain cases separately If the non-drain case is chosen with a receiver_amount equivalent to what drain would have calculated, it results in an error. For drain, the caller has to explicitly choose PayOnchainAmount::Drain. * CLI: send-onchain-payment accepts optional amount * CLI: add docs for send-onchain-payment drain arg * SDK: expand docs for prepare_pay_onchain * Re-generate RN bindings * Re-generate flutter bindings
This commit is contained in:
@@ -47,10 +47,14 @@ pub(crate) enum Command {
|
|||||||
/// Btc onchain address to send to
|
/// Btc onchain address to send to
|
||||||
address: String,
|
address: String,
|
||||||
|
|
||||||
/// Amount that will be received, in satoshi
|
/// Amount that will be received, in satoshi. Must be set if `drain` is false or unset.
|
||||||
receiver_amount_sat: u64,
|
receiver_amount_sat: Option<u64>,
|
||||||
|
|
||||||
// The optional fee rate to use, in satoshi/vbyte
|
/// Whether or not this is a drain operation. If true, all available funds will be used.
|
||||||
|
#[arg(short, long)]
|
||||||
|
drain: Option<bool>,
|
||||||
|
|
||||||
|
/// The optional fee rate to use, in satoshi/vbyte
|
||||||
#[clap(short = 'f', long = "fee_rate")]
|
#[clap(short = 'f', long = "fee_rate")]
|
||||||
sat_per_vbyte: Option<u32>,
|
sat_per_vbyte: Option<u32>,
|
||||||
},
|
},
|
||||||
@@ -341,19 +345,28 @@ pub(crate) async fn handle_command(
|
|||||||
Command::SendOnchainPayment {
|
Command::SendOnchainPayment {
|
||||||
address,
|
address,
|
||||||
receiver_amount_sat,
|
receiver_amount_sat,
|
||||||
|
drain,
|
||||||
sat_per_vbyte,
|
sat_per_vbyte,
|
||||||
} => {
|
} => {
|
||||||
|
let amount = match drain.unwrap_or(false) {
|
||||||
|
true => PayOnchainAmount::Drain,
|
||||||
|
false => PayOnchainAmount::Receiver {
|
||||||
|
amount_sat: receiver_amount_sat.ok_or(anyhow::anyhow!(
|
||||||
|
"Must specify `receiver_amount_sat` if not draining"
|
||||||
|
))?,
|
||||||
|
},
|
||||||
|
};
|
||||||
let prepare_response = sdk
|
let prepare_response = sdk
|
||||||
.prepare_pay_onchain(&PreparePayOnchainRequest {
|
.prepare_pay_onchain(&PreparePayOnchainRequest {
|
||||||
receiver_amount_sat,
|
amount,
|
||||||
sat_per_vbyte,
|
sat_per_vbyte,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
wait_confirmation!(
|
wait_confirmation!(
|
||||||
format!(
|
format!(
|
||||||
"Fees: {} sat (incl claim fee: {} sat). Are the fees acceptable? (y/N) ",
|
"Fees: {} sat (incl claim fee: {} sat). Receiver amount: {} sat. Are the fees acceptable? (y/N) ",
|
||||||
prepare_response.total_fees_sat, prepare_response.claim_fees_sat
|
prepare_response.total_fees_sat, prepare_response.claim_fees_sat, prepare_response.receiver_amount_sat
|
||||||
),
|
),
|
||||||
"Payment send halted"
|
"Payment send halted"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -133,8 +133,21 @@ typedef struct wire_cst_prepare_buy_bitcoin_request {
|
|||||||
uint64_t amount_sat;
|
uint64_t amount_sat;
|
||||||
} wire_cst_prepare_buy_bitcoin_request;
|
} wire_cst_prepare_buy_bitcoin_request;
|
||||||
|
|
||||||
|
typedef struct wire_cst_PayOnchainAmount_Receiver {
|
||||||
|
uint64_t amount_sat;
|
||||||
|
} wire_cst_PayOnchainAmount_Receiver;
|
||||||
|
|
||||||
|
typedef union PayOnchainAmountKind {
|
||||||
|
struct wire_cst_PayOnchainAmount_Receiver Receiver;
|
||||||
|
} PayOnchainAmountKind;
|
||||||
|
|
||||||
|
typedef struct wire_cst_pay_onchain_amount {
|
||||||
|
int32_t tag;
|
||||||
|
union PayOnchainAmountKind kind;
|
||||||
|
} wire_cst_pay_onchain_amount;
|
||||||
|
|
||||||
typedef struct wire_cst_prepare_pay_onchain_request {
|
typedef struct wire_cst_prepare_pay_onchain_request {
|
||||||
uint64_t receiver_amount_sat;
|
struct wire_cst_pay_onchain_amount amount;
|
||||||
uint32_t *sat_per_vbyte;
|
uint32_t *sat_per_vbyte;
|
||||||
} wire_cst_prepare_pay_onchain_request;
|
} wire_cst_prepare_pay_onchain_request;
|
||||||
|
|
||||||
|
|||||||
@@ -410,8 +410,14 @@ dictionary OnchainPaymentLimitsResponse {
|
|||||||
Limits receive;
|
Limits receive;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[Enum]
|
||||||
|
interface PayOnchainAmount {
|
||||||
|
Receiver(u64 amount_sat);
|
||||||
|
Drain();
|
||||||
|
};
|
||||||
|
|
||||||
dictionary PreparePayOnchainRequest {
|
dictionary PreparePayOnchainRequest {
|
||||||
u64 receiver_amount_sat;
|
PayOnchainAmount amount;
|
||||||
u32? sat_per_vbyte = null;
|
u32? sat_per_vbyte = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -582,14 +582,28 @@ impl ChainSwapStateHandler {
|
|||||||
lockup_details.amount, lockup_details.lockup_address
|
lockup_details.amount, lockup_details.lockup_address
|
||||||
);
|
);
|
||||||
|
|
||||||
let lockup_tx = self
|
let lockup_tx = match self
|
||||||
.onchain_wallet
|
.onchain_wallet
|
||||||
.build_tx(
|
.build_tx(
|
||||||
None,
|
None,
|
||||||
&lockup_details.lockup_address,
|
&lockup_details.lockup_address,
|
||||||
lockup_details.amount as u64,
|
lockup_details.amount as u64,
|
||||||
)
|
)
|
||||||
.await?;
|
.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 as u64),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
Ok(lockup_tx) => Ok(lockup_tx),
|
||||||
|
}?;
|
||||||
|
|
||||||
let lockup_tx_id = self
|
let lockup_tx_id = self
|
||||||
.liquid_chain_service
|
.liquid_chain_service
|
||||||
|
|||||||
@@ -3062,6 +3062,27 @@ impl SseDecode for Option<Vec<crate::model::PaymentType>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseDecode for crate::model::PayOnchainAmount {
|
||||||
|
// 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_ = <i32>::sse_decode(deserializer);
|
||||||
|
match tag_ {
|
||||||
|
0 => {
|
||||||
|
let mut var_amountSat = <u64>::sse_decode(deserializer);
|
||||||
|
return crate::model::PayOnchainAmount::Receiver {
|
||||||
|
amount_sat: var_amountSat,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
1 => {
|
||||||
|
return crate::model::PayOnchainAmount::Drain;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unimplemented!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseDecode for crate::model::PayOnchainRequest {
|
impl SseDecode for crate::model::PayOnchainRequest {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
@@ -3307,10 +3328,10 @@ impl SseDecode for crate::model::PrepareBuyBitcoinResponse {
|
|||||||
impl SseDecode for crate::model::PreparePayOnchainRequest {
|
impl SseDecode for crate::model::PreparePayOnchainRequest {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
|
||||||
let mut var_receiverAmountSat = <u64>::sse_decode(deserializer);
|
let mut var_amount = <crate::model::PayOnchainAmount>::sse_decode(deserializer);
|
||||||
let mut var_satPerVbyte = <Option<u32>>::sse_decode(deserializer);
|
let mut var_satPerVbyte = <Option<u32>>::sse_decode(deserializer);
|
||||||
return crate::model::PreparePayOnchainRequest {
|
return crate::model::PreparePayOnchainRequest {
|
||||||
receiver_amount_sat: var_receiverAmountSat,
|
amount: var_amount,
|
||||||
sat_per_vbyte: var_satPerVbyte,
|
sat_per_vbyte: var_satPerVbyte,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -4828,6 +4849,31 @@ impl flutter_rust_bridge::IntoIntoDart<crate::model::OnchainPaymentLimitsRespons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
impl flutter_rust_bridge::IntoDart for crate::model::PayOnchainAmount {
|
||||||
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
|
match self {
|
||||||
|
crate::model::PayOnchainAmount::Receiver { amount_sat } => {
|
||||||
|
[0.into_dart(), amount_sat.into_into_dart().into_dart()].into_dart()
|
||||||
|
}
|
||||||
|
crate::model::PayOnchainAmount::Drain => [1.into_dart()].into_dart(),
|
||||||
|
_ => {
|
||||||
|
unimplemented!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
|
||||||
|
for crate::model::PayOnchainAmount
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl flutter_rust_bridge::IntoIntoDart<crate::model::PayOnchainAmount>
|
||||||
|
for crate::model::PayOnchainAmount
|
||||||
|
{
|
||||||
|
fn into_into_dart(self) -> crate::model::PayOnchainAmount {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
impl flutter_rust_bridge::IntoDart for crate::model::PayOnchainRequest {
|
impl flutter_rust_bridge::IntoDart for crate::model::PayOnchainRequest {
|
||||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
[
|
[
|
||||||
@@ -5090,7 +5136,7 @@ impl flutter_rust_bridge::IntoIntoDart<crate::model::PrepareBuyBitcoinResponse>
|
|||||||
impl flutter_rust_bridge::IntoDart for crate::model::PreparePayOnchainRequest {
|
impl flutter_rust_bridge::IntoDart for crate::model::PreparePayOnchainRequest {
|
||||||
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
|
||||||
[
|
[
|
||||||
self.receiver_amount_sat.into_into_dart().into_dart(),
|
self.amount.into_into_dart().into_dart(),
|
||||||
self.sat_per_vbyte.into_into_dart().into_dart(),
|
self.sat_per_vbyte.into_into_dart().into_dart(),
|
||||||
]
|
]
|
||||||
.into_dart()
|
.into_dart()
|
||||||
@@ -6532,6 +6578,24 @@ impl SseEncode for Option<Vec<crate::model::PaymentType>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SseEncode for crate::model::PayOnchainAmount {
|
||||||
|
// 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 } => {
|
||||||
|
<i32>::sse_encode(0, serializer);
|
||||||
|
<u64>::sse_encode(amount_sat, serializer);
|
||||||
|
}
|
||||||
|
crate::model::PayOnchainAmount::Drain => {
|
||||||
|
<i32>::sse_encode(1, serializer);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unimplemented!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SseEncode for crate::model::PayOnchainRequest {
|
impl SseEncode for crate::model::PayOnchainRequest {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
@@ -6760,7 +6824,7 @@ impl SseEncode for crate::model::PrepareBuyBitcoinResponse {
|
|||||||
impl SseEncode for crate::model::PreparePayOnchainRequest {
|
impl SseEncode for crate::model::PreparePayOnchainRequest {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
|
||||||
<u64>::sse_encode(self.receiver_amount_sat, serializer);
|
<crate::model::PayOnchainAmount>::sse_encode(self.amount, serializer);
|
||||||
<Option<u32>>::sse_encode(self.sat_per_vbyte, serializer);
|
<Option<u32>>::sse_encode(self.sat_per_vbyte, serializer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8227,6 +8291,21 @@ mod io {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl CstDecode<crate::model::PayOnchainAmount> for wire_cst_pay_onchain_amount {
|
||||||
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
|
fn cst_decode(self) -> crate::model::PayOnchainAmount {
|
||||||
|
match self.tag {
|
||||||
|
0 => {
|
||||||
|
let ans = unsafe { self.kind.Receiver };
|
||||||
|
crate::model::PayOnchainAmount::Receiver {
|
||||||
|
amount_sat: ans.amount_sat.cst_decode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 => crate::model::PayOnchainAmount::Drain,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl CstDecode<crate::model::PayOnchainRequest> for wire_cst_pay_onchain_request {
|
impl CstDecode<crate::model::PayOnchainRequest> for wire_cst_pay_onchain_request {
|
||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
fn cst_decode(self) -> crate::model::PayOnchainRequest {
|
fn cst_decode(self) -> crate::model::PayOnchainRequest {
|
||||||
@@ -8389,7 +8468,7 @@ mod io {
|
|||||||
// Codec=Cst (C-struct based), see doc to use other codecs
|
// Codec=Cst (C-struct based), see doc to use other codecs
|
||||||
fn cst_decode(self) -> crate::model::PreparePayOnchainRequest {
|
fn cst_decode(self) -> crate::model::PreparePayOnchainRequest {
|
||||||
crate::model::PreparePayOnchainRequest {
|
crate::model::PreparePayOnchainRequest {
|
||||||
receiver_amount_sat: self.receiver_amount_sat.cst_decode(),
|
amount: self.amount.cst_decode(),
|
||||||
sat_per_vbyte: self.sat_per_vbyte.cst_decode(),
|
sat_per_vbyte: self.sat_per_vbyte.cst_decode(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9277,6 +9356,19 @@ mod io {
|
|||||||
Self::new_with_null_ptr()
|
Self::new_with_null_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl NewWithNullPtr for wire_cst_pay_onchain_amount {
|
||||||
|
fn new_with_null_ptr() -> Self {
|
||||||
|
Self {
|
||||||
|
tag: -1,
|
||||||
|
kind: PayOnchainAmountKind { nil__: () },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for wire_cst_pay_onchain_amount {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new_with_null_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
impl NewWithNullPtr for wire_cst_pay_onchain_request {
|
impl NewWithNullPtr for wire_cst_pay_onchain_request {
|
||||||
fn new_with_null_ptr() -> Self {
|
fn new_with_null_ptr() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -9365,7 +9457,7 @@ mod io {
|
|||||||
impl NewWithNullPtr for wire_cst_prepare_pay_onchain_request {
|
impl NewWithNullPtr for wire_cst_prepare_pay_onchain_request {
|
||||||
fn new_with_null_ptr() -> Self {
|
fn new_with_null_ptr() -> Self {
|
||||||
Self {
|
Self {
|
||||||
receiver_amount_sat: Default::default(),
|
amount: Default::default(),
|
||||||
sat_per_vbyte: core::ptr::null_mut(),
|
sat_per_vbyte: core::ptr::null_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11123,6 +11215,23 @@ mod io {
|
|||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct wire_cst_pay_onchain_amount {
|
||||||
|
tag: i32,
|
||||||
|
kind: PayOnchainAmountKind,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub union PayOnchainAmountKind {
|
||||||
|
Receiver: wire_cst_PayOnchainAmount_Receiver,
|
||||||
|
nil__: (),
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct wire_cst_PayOnchainAmount_Receiver {
|
||||||
|
amount_sat: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub struct wire_cst_pay_onchain_request {
|
pub struct wire_cst_pay_onchain_request {
|
||||||
address: *mut wire_cst_list_prim_u_8_strict,
|
address: *mut wire_cst_list_prim_u_8_strict,
|
||||||
prepare_response: wire_cst_prepare_pay_onchain_response,
|
prepare_response: wire_cst_prepare_pay_onchain_response,
|
||||||
@@ -11265,7 +11374,7 @@ mod io {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct wire_cst_prepare_pay_onchain_request {
|
pub struct wire_cst_prepare_pay_onchain_request {
|
||||||
receiver_amount_sat: u64,
|
amount: wire_cst_pay_onchain_amount,
|
||||||
sat_per_vbyte: *mut u32,
|
sat_per_vbyte: *mut u32,
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|||||||
@@ -307,10 +307,19 @@ pub struct SendPaymentResponse {
|
|||||||
pub payment: Payment,
|
pub payment: Payment,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Clone)]
|
||||||
|
pub enum PayOnchainAmount {
|
||||||
|
/// The amount in satoshi that will be received
|
||||||
|
Receiver { amount_sat: u64 },
|
||||||
|
/// Indicates that all available funds should be sent
|
||||||
|
Drain,
|
||||||
|
}
|
||||||
|
|
||||||
/// An argument when calling [crate::sdk::LiquidSdk::prepare_pay_onchain].
|
/// An argument when calling [crate::sdk::LiquidSdk::prepare_pay_onchain].
|
||||||
#[derive(Debug, Serialize, Clone)]
|
#[derive(Debug, Serialize, Clone)]
|
||||||
pub struct PreparePayOnchainRequest {
|
pub struct PreparePayOnchainRequest {
|
||||||
pub receiver_amount_sat: u64,
|
pub amount: PayOnchainAmount,
|
||||||
|
/// The optional fee rate of the Bitcoin claim transaction. Defaults to the swapper estimated claim fee.
|
||||||
pub sat_per_vbyte: Option<u32>,
|
pub sat_per_vbyte: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -688,16 +688,24 @@ impl LiquidSdk {
|
|||||||
.sum())
|
.sum())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn estimate_lockup_tx_fee(&self, amount_sat: u64) -> Result<u64, PaymentError> {
|
fn get_temp_p2tr_addr(&self) -> &str {
|
||||||
// TODO Replace this with own address when LWK supports taproot
|
// TODO Replace this with own address when LWK supports taproot
|
||||||
// https://github.com/Blockstream/lwk/issues/31
|
// https://github.com/Blockstream/lwk/issues/31
|
||||||
let temp_p2tr_addr = match self.config.network {
|
match self.config.network {
|
||||||
LiquidNetwork::Mainnet => "lq1pqvzxvqhrf54dd4sny4cag7497pe38252qefk46t92frs7us8r80ja9ha8r5me09nn22m4tmdqp5p4wafq3s59cql3v9n45t5trwtxrmxfsyxjnstkctj",
|
LiquidNetwork::Mainnet => "lq1pqvzxvqhrf54dd4sny4cag7497pe38252qefk46t92frs7us8r80ja9ha8r5me09nn22m4tmdqp5p4wafq3s59cql3v9n45t5trwtxrmxfsyxjnstkctj",
|
||||||
LiquidNetwork::Testnet => "tlq1pq0wqu32e2xacxeyps22x8gjre4qk3u6r70pj4r62hzczxeyz8x3yxucrpn79zy28plc4x37aaf33kwt6dz2nn6gtkya6h02mwpzy4eh69zzexq7cf5y5"
|
LiquidNetwork::Testnet => "tlq1pq0wqu32e2xacxeyps22x8gjre4qk3u6r70pj4r62hzczxeyz8x3yxucrpn79zy28plc4x37aaf33kwt6dz2nn6gtkya6h02mwpzy4eh69zzexq7cf5y5"
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Estimate the lockup tx fee for Send swaps
|
||||||
|
async fn estimate_lockup_tx_fee_send(
|
||||||
|
&self,
|
||||||
|
user_lockup_amount_sat: u64,
|
||||||
|
) -> Result<u64, PaymentError> {
|
||||||
|
let temp_p2tr_addr = self.get_temp_p2tr_addr();
|
||||||
|
|
||||||
self.estimate_onchain_tx_fee(
|
self.estimate_onchain_tx_fee(
|
||||||
amount_sat,
|
user_lockup_amount_sat,
|
||||||
temp_p2tr_addr,
|
temp_p2tr_addr,
|
||||||
self.config
|
self.config
|
||||||
.lowball_fee_rate_msat_per_vbyte()
|
.lowball_fee_rate_msat_per_vbyte()
|
||||||
@@ -706,6 +714,31 @@ impl LiquidSdk {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Estimate the lockup tx fee for Chain Send swaps
|
||||||
|
async fn estimate_lockup_tx_fee_chain_send(
|
||||||
|
&self,
|
||||||
|
user_lockup_amount_sat: u64,
|
||||||
|
) -> Result<u64, PaymentError> {
|
||||||
|
let temp_p2tr_addr = self.get_temp_p2tr_addr();
|
||||||
|
|
||||||
|
self.estimate_onchain_tx_fee(user_lockup_amount_sat, temp_p2tr_addr, None)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn estimate_drain_tx_fee(&self) -> Result<u64, PaymentError> {
|
||||||
|
let temp_p2tr_addr = self.get_temp_p2tr_addr();
|
||||||
|
|
||||||
|
let fee_sat = self
|
||||||
|
.onchain_wallet
|
||||||
|
.build_drain_tx(None, temp_p2tr_addr, None)
|
||||||
|
.await?
|
||||||
|
.all_fees()
|
||||||
|
.values()
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
Ok(fee_sat)
|
||||||
|
}
|
||||||
|
|
||||||
/// Prepares to pay a Lightning invoice via a submarine swap.
|
/// Prepares to pay a Lightning invoice via a submarine swap.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@@ -792,7 +825,7 @@ impl LiquidSdk {
|
|||||||
None => {
|
None => {
|
||||||
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
||||||
let lockup_fees_sat = self
|
let lockup_fees_sat = self
|
||||||
.estimate_lockup_tx_fee(receiver_amount_sat + boltz_fees_total)
|
.estimate_lockup_tx_fee_send(receiver_amount_sat + boltz_fees_total)
|
||||||
.await?;
|
.await?;
|
||||||
boltz_fees_total + lockup_fees_sat
|
boltz_fees_total + lockup_fees_sat
|
||||||
}
|
}
|
||||||
@@ -1002,7 +1035,7 @@ impl LiquidSdk {
|
|||||||
|
|
||||||
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
let boltz_fees_total = lbtc_pair.fees.total(receiver_amount_sat);
|
||||||
let lockup_tx_fees_sat = self
|
let lockup_tx_fees_sat = self
|
||||||
.estimate_lockup_tx_fee(receiver_amount_sat + boltz_fees_total)
|
.estimate_lockup_tx_fee_send(receiver_amount_sat + boltz_fees_total)
|
||||||
.await?;
|
.await?;
|
||||||
ensure_sdk!(
|
ensure_sdk!(
|
||||||
fees_sat == boltz_fees_total + lockup_tx_fees_sat,
|
fees_sat == boltz_fees_total + lockup_tx_fees_sat,
|
||||||
@@ -1142,7 +1175,8 @@ impl LiquidSdk {
|
|||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `req` - the [PreparePayOnchainRequest] containing:
|
/// * `req` - the [PreparePayOnchainRequest] containing:
|
||||||
/// * `receiver_amount_sat` - the amount in satoshi that will be received
|
/// * `amount` - which can be of two types: [PayOnchainAmount::Drain], which uses all funds,
|
||||||
|
/// and [PayOnchainAmount::Receiver], which sets the amount the receiver should receive
|
||||||
/// * `sat_per_vbyte` - the optional fee rate of the Bitcoin claim transaction. Defaults to the swapper estimated claim fee
|
/// * `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(
|
pub async fn prepare_pay_onchain(
|
||||||
&self,
|
&self,
|
||||||
@@ -1150,7 +1184,7 @@ impl LiquidSdk {
|
|||||||
) -> Result<PreparePayOnchainResponse, PaymentError> {
|
) -> Result<PreparePayOnchainResponse, PaymentError> {
|
||||||
self.ensure_is_started().await?;
|
self.ensure_is_started().await?;
|
||||||
|
|
||||||
let receiver_amount_sat = req.receiver_amount_sat;
|
let balance_sat = self.get_info().await?.balance_sat;
|
||||||
let pair = self.get_chain_pair(Direction::Outgoing)?;
|
let pair = self.get_chain_pair(Direction::Outgoing)?;
|
||||||
let claim_fees_sat = match req.sat_per_vbyte {
|
let claim_fees_sat = match req.sat_per_vbyte {
|
||||||
Some(sat_per_vbyte) => ESTIMATED_BTC_CLAIM_TX_VSIZE * sat_per_vbyte as u64,
|
Some(sat_per_vbyte) => ESTIMATED_BTC_CLAIM_TX_VSIZE * sat_per_vbyte as u64,
|
||||||
@@ -1158,22 +1192,57 @@ impl LiquidSdk {
|
|||||||
};
|
};
|
||||||
let server_fees_sat = pair.fees.server();
|
let server_fees_sat = pair.fees.server();
|
||||||
|
|
||||||
|
let (payer_amount_sat, receiver_amount_sat, total_fees_sat) = match req.amount {
|
||||||
|
PayOnchainAmount::Receiver { amount_sat } => {
|
||||||
|
let receiver_amount_sat = amount_sat;
|
||||||
|
|
||||||
let user_lockup_amount_sat_without_service_fee =
|
let user_lockup_amount_sat_without_service_fee =
|
||||||
receiver_amount_sat + claim_fees_sat + server_fees_sat;
|
receiver_amount_sat + claim_fees_sat + server_fees_sat;
|
||||||
let boltz_fees_sat = pair.fees.boltz(user_lockup_amount_sat_without_service_fee);
|
|
||||||
let user_lockup_amount_sat = user_lockup_amount_sat_without_service_fee + boltz_fees_sat;
|
// The resulting invoice amount contains the service fee, which is rounded up with ceil()
|
||||||
|
// Therefore, when calculating the user_lockup amount, we must also round it up with ceil()
|
||||||
|
let user_lockup_amount_sat = (user_lockup_amount_sat_without_service_fee as f64
|
||||||
|
* 100.0
|
||||||
|
/ (100.0 - pair.fees.percentage))
|
||||||
|
.ceil() as u64;
|
||||||
self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?;
|
self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?;
|
||||||
let lockup_fees_sat = self.estimate_lockup_tx_fee(user_lockup_amount_sat).await?;
|
|
||||||
|
let lockup_fees_sat = self
|
||||||
|
.estimate_lockup_tx_fee_chain_send(user_lockup_amount_sat)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let boltz_fees_sat =
|
||||||
|
user_lockup_amount_sat - user_lockup_amount_sat_without_service_fee;
|
||||||
|
let total_fees_sat =
|
||||||
|
boltz_fees_sat + lockup_fees_sat + claim_fees_sat + server_fees_sat;
|
||||||
|
let payer_amount_sat = receiver_amount_sat + total_fees_sat;
|
||||||
|
|
||||||
|
(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?;
|
||||||
|
|
||||||
|
let user_lockup_amount_sat = payer_amount_sat - lockup_fees_sat;
|
||||||
|
self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?;
|
||||||
|
|
||||||
|
let boltz_fees_sat = pair.fees.boltz(user_lockup_amount_sat);
|
||||||
|
let total_fees_sat =
|
||||||
|
boltz_fees_sat + lockup_fees_sat + claim_fees_sat + server_fees_sat;
|
||||||
|
let receiver_amount_sat = payer_amount_sat - total_fees_sat;
|
||||||
|
|
||||||
|
(payer_amount_sat, receiver_amount_sat, total_fees_sat)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let res = PreparePayOnchainResponse {
|
let res = PreparePayOnchainResponse {
|
||||||
receiver_amount_sat,
|
receiver_amount_sat,
|
||||||
claim_fees_sat,
|
claim_fees_sat,
|
||||||
total_fees_sat: boltz_fees_sat + lockup_fees_sat + claim_fees_sat + server_fees_sat,
|
total_fees_sat,
|
||||||
};
|
};
|
||||||
|
|
||||||
let payer_amount_sat = res.receiver_amount_sat + res.total_fees_sat;
|
|
||||||
ensure_sdk!(
|
ensure_sdk!(
|
||||||
payer_amount_sat <= self.get_info().await?.balance_sat,
|
payer_amount_sat <= balance_sat,
|
||||||
PaymentError::InsufficientFunds
|
PaymentError::InsufficientFunds
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1202,6 +1271,7 @@ impl LiquidSdk {
|
|||||||
) -> Result<SendPaymentResponse, PaymentError> {
|
) -> Result<SendPaymentResponse, PaymentError> {
|
||||||
self.ensure_is_started().await?;
|
self.ensure_is_started().await?;
|
||||||
|
|
||||||
|
let balance_sat = self.get_info().await?.balance_sat;
|
||||||
let receiver_amount_sat = req.prepare_response.receiver_amount_sat;
|
let receiver_amount_sat = req.prepare_response.receiver_amount_sat;
|
||||||
let pair = self.get_chain_pair(Direction::Outgoing)?;
|
let pair = self.get_chain_pair(Direction::Outgoing)?;
|
||||||
let claim_fees_sat = req.prepare_response.claim_fees_sat;
|
let claim_fees_sat = req.prepare_response.claim_fees_sat;
|
||||||
@@ -1210,10 +1280,24 @@ impl LiquidSdk {
|
|||||||
|
|
||||||
let user_lockup_amount_sat_without_service_fee =
|
let user_lockup_amount_sat_without_service_fee =
|
||||||
receiver_amount_sat + claim_fees_sat + server_fees_sat;
|
receiver_amount_sat + claim_fees_sat + server_fees_sat;
|
||||||
let boltz_fee_sat = pair.fees.boltz(user_lockup_amount_sat_without_service_fee);
|
|
||||||
let user_lockup_amount_sat = user_lockup_amount_sat_without_service_fee + boltz_fee_sat;
|
// The resulting invoice amount contains the service fee, which is rounded up with ceil()
|
||||||
|
// Therefore, when calculating the user_lockup amount, we must also round it up with ceil()
|
||||||
|
let user_lockup_amount_sat = (user_lockup_amount_sat_without_service_fee as f64 * 100.0
|
||||||
|
/ (100.0 - pair.fees.percentage))
|
||||||
|
.ceil() as u64;
|
||||||
|
let boltz_fee_sat = user_lockup_amount_sat - user_lockup_amount_sat_without_service_fee;
|
||||||
self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?;
|
self.validate_user_lockup_amount_for_chain_pair(&pair, user_lockup_amount_sat)?;
|
||||||
let lockup_fees_sat = self.estimate_lockup_tx_fee(user_lockup_amount_sat).await?;
|
|
||||||
|
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?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ensure_sdk!(
|
ensure_sdk!(
|
||||||
req.prepare_response.total_fees_sat
|
req.prepare_response.total_fees_sat
|
||||||
@@ -1221,9 +1305,8 @@ impl LiquidSdk {
|
|||||||
PaymentError::InvalidOrExpiredFees
|
PaymentError::InvalidOrExpiredFees
|
||||||
);
|
);
|
||||||
|
|
||||||
let payer_amount_sat = req.prepare_response.total_fees_sat + receiver_amount_sat;
|
|
||||||
ensure_sdk!(
|
ensure_sdk!(
|
||||||
payer_amount_sat <= self.get_info().await?.balance_sat,
|
payer_amount_sat <= balance_sat,
|
||||||
PaymentError::InsufficientFunds
|
PaymentError::InsufficientFunds
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1623,17 +1706,17 @@ impl LiquidSdk {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_chain_swap(
|
async fn create_receive_chain_swap(
|
||||||
&self,
|
&self,
|
||||||
payer_amount_sat: u64,
|
user_lockup_amount_sat: u64,
|
||||||
fees_sat: u64,
|
fees_sat: u64,
|
||||||
) -> Result<ChainSwap, PaymentError> {
|
) -> Result<ChainSwap, PaymentError> {
|
||||||
let pair = self.get_and_validate_chain_pair(Direction::Incoming, payer_amount_sat)?;
|
let pair = self.get_and_validate_chain_pair(Direction::Incoming, user_lockup_amount_sat)?;
|
||||||
let claim_fees_sat = pair.fees.claim_estimate();
|
let claim_fees_sat = pair.fees.claim_estimate();
|
||||||
let server_fees_sat = pair.fees.server();
|
let server_fees_sat = pair.fees.server();
|
||||||
|
|
||||||
ensure_sdk!(
|
ensure_sdk!(
|
||||||
fees_sat == pair.fees.boltz(payer_amount_sat) + claim_fees_sat + server_fees_sat,
|
fees_sat == pair.fees.boltz(user_lockup_amount_sat) + claim_fees_sat + server_fees_sat,
|
||||||
PaymentError::InvalidOrExpiredFees
|
PaymentError::InvalidOrExpiredFees
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1665,7 +1748,7 @@ impl LiquidSdk {
|
|||||||
preimage_hash: preimage.sha256,
|
preimage_hash: preimage.sha256,
|
||||||
claim_public_key: Some(claim_public_key),
|
claim_public_key: Some(claim_public_key),
|
||||||
refund_public_key: Some(refund_public_key),
|
refund_public_key: Some(refund_public_key),
|
||||||
user_lock_amount: Some(payer_amount_sat as u32), // TODO update our model
|
user_lock_amount: Some(user_lockup_amount_sat as u32), // TODO update our model
|
||||||
server_lock_amount: None,
|
server_lock_amount: None,
|
||||||
pair_hash: Some(pair.hash),
|
pair_hash: Some(pair.hash),
|
||||||
referral_id: None,
|
referral_id: None,
|
||||||
@@ -1676,8 +1759,8 @@ impl LiquidSdk {
|
|||||||
let create_response_json =
|
let create_response_json =
|
||||||
ChainSwap::from_boltz_struct_to_json(&create_response, &swap_id)?;
|
ChainSwap::from_boltz_struct_to_json(&create_response, &swap_id)?;
|
||||||
|
|
||||||
let accept_zero_conf = payer_amount_sat <= pair.limits.maximal_zero_conf;
|
let accept_zero_conf = user_lockup_amount_sat <= pair.limits.maximal_zero_conf;
|
||||||
let receiver_amount_sat = payer_amount_sat - fees_sat;
|
let receiver_amount_sat = user_lockup_amount_sat - fees_sat;
|
||||||
let claim_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
let claim_address = self.onchain_wallet.next_unused_address().await?.to_string();
|
||||||
|
|
||||||
let swap = ChainSwap {
|
let swap = ChainSwap {
|
||||||
@@ -1688,7 +1771,7 @@ impl LiquidSdk {
|
|||||||
timeout_block_height: create_response.lockup_details.timeout_block_height,
|
timeout_block_height: create_response.lockup_details.timeout_block_height,
|
||||||
preimage: preimage_str,
|
preimage: preimage_str,
|
||||||
description: Some("Bitcoin transfer".to_string()),
|
description: Some("Bitcoin transfer".to_string()),
|
||||||
payer_amount_sat,
|
payer_amount_sat: user_lockup_amount_sat,
|
||||||
receiver_amount_sat,
|
receiver_amount_sat,
|
||||||
claim_fees_sat,
|
claim_fees_sat,
|
||||||
accept_zero_conf,
|
accept_zero_conf,
|
||||||
@@ -1715,7 +1798,9 @@ impl LiquidSdk {
|
|||||||
) -> Result<ReceivePaymentResponse, PaymentError> {
|
) -> Result<ReceivePaymentResponse, PaymentError> {
|
||||||
self.ensure_is_started().await?;
|
self.ensure_is_started().await?;
|
||||||
|
|
||||||
let swap = self.create_chain_swap(payer_amount_sat, fees_sat).await?;
|
let swap = self
|
||||||
|
.create_receive_chain_swap(payer_amount_sat, fees_sat)
|
||||||
|
.await?;
|
||||||
let create_response = swap.get_boltz_create_response()?;
|
let create_response = swap.get_boltz_create_response()?;
|
||||||
let address = create_response.lockup_details.lockup_address;
|
let address = create_response.lockup_details.lockup_address;
|
||||||
|
|
||||||
@@ -1836,7 +1921,7 @@ impl LiquidSdk {
|
|||||||
/// * `redirect_url` - the optional redirect URL the provider should redirect to after purchase
|
/// * `redirect_url` - the optional redirect URL the provider should redirect to after purchase
|
||||||
pub async fn buy_bitcoin(&self, req: &BuyBitcoinRequest) -> Result<String, PaymentError> {
|
pub async fn buy_bitcoin(&self, req: &BuyBitcoinRequest) -> Result<String, PaymentError> {
|
||||||
let swap = self
|
let swap = self
|
||||||
.create_chain_swap(
|
.create_receive_chain_swap(
|
||||||
req.prepare_response.amount_sat,
|
req.prepare_response.amount_sat,
|
||||||
req.prepare_response.fees_sat,
|
req.prepare_response.fees_sat,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ impl OnchainWallet for MockWallet {
|
|||||||
Ok(TEST_LIQUID_TX.clone())
|
Ok(TEST_LIQUID_TX.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn build_drain_tx(
|
||||||
|
&self,
|
||||||
|
_fee_rate_sats_per_kvb: Option<f32>,
|
||||||
|
_recipient_address: &str,
|
||||||
|
_enforce_amount_sat: Option<u64>,
|
||||||
|
) -> Result<Transaction, PaymentError> {
|
||||||
|
Ok(TEST_LIQUID_TX.clone())
|
||||||
|
}
|
||||||
|
|
||||||
async fn next_unused_address(&self) -> Result<Address, PaymentError> {
|
async fn next_unused_address(&self) -> Result<Address, PaymentError> {
|
||||||
Ok(TEST_P2TR_ADDR.clone())
|
Ok(TEST_P2TR_ADDR.clone())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use sdk_common::lightning::util::message_signing::verify;
|
|||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ensure_sdk,
|
||||||
error::PaymentError,
|
error::PaymentError,
|
||||||
model::{Config, LiquidNetwork},
|
model::{Config, LiquidNetwork},
|
||||||
};
|
};
|
||||||
@@ -38,6 +39,20 @@ pub trait OnchainWallet: Send + Sync {
|
|||||||
amount_sat: u64,
|
amount_sat: u64,
|
||||||
) -> Result<Transaction, PaymentError>;
|
) -> Result<Transaction, PaymentError>;
|
||||||
|
|
||||||
|
/// Builds a drain tx.
|
||||||
|
///
|
||||||
|
/// ### Arguments
|
||||||
|
/// - `fee_rate_sats_per_kvb`: custom drain tx feerate
|
||||||
|
/// - `recipient_address`: drain tx recipient
|
||||||
|
/// - `enforce_amount_sat`: if set, the drain tx will only be built if the amount transferred is
|
||||||
|
/// this amount, otherwise it will fail with a validation error
|
||||||
|
async fn build_drain_tx(
|
||||||
|
&self,
|
||||||
|
fee_rate_sats_per_kvb: Option<f32>,
|
||||||
|
recipient_address: &str,
|
||||||
|
enforce_amount_sat: Option<u64>,
|
||||||
|
) -> Result<Transaction, PaymentError>;
|
||||||
|
|
||||||
/// Get the next unused address in the wallet
|
/// Get the next unused address in the wallet
|
||||||
async fn next_unused_address(&self) -> Result<Address, PaymentError>;
|
async fn next_unused_address(&self) -> Result<Address, PaymentError>;
|
||||||
|
|
||||||
@@ -139,6 +154,49 @@ impl OnchainWallet for LiquidOnchainWallet {
|
|||||||
Ok(lwk_wollet.finalize(&mut pset)?)
|
Ok(lwk_wollet.finalize(&mut pset)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn build_drain_tx(
|
||||||
|
&self,
|
||||||
|
fee_rate_sats_per_kvb: Option<f32>,
|
||||||
|
recipient_address: &str,
|
||||||
|
enforce_amount_sat: Option<u64>,
|
||||||
|
) -> Result<Transaction, PaymentError> {
|
||||||
|
let lwk_wollet = self.wallet.lock().await;
|
||||||
|
|
||||||
|
let address =
|
||||||
|
ElementsAddress::from_str(recipient_address).map_err(|e| PaymentError::Generic {
|
||||||
|
err: format!(
|
||||||
|
"Recipient address {recipient_address} is not a valid ElementsAddress: {e:?}"
|
||||||
|
),
|
||||||
|
})?;
|
||||||
|
let mut pset = lwk_wollet
|
||||||
|
.tx_builder()
|
||||||
|
.drain_lbtc_wallet()
|
||||||
|
.drain_lbtc_to(address)
|
||||||
|
.fee_rate(fee_rate_sats_per_kvb)
|
||||||
|
.finish()?;
|
||||||
|
|
||||||
|
if let Some(enforce_amount_sat) = enforce_amount_sat {
|
||||||
|
let pset_details = lwk_wollet.get_details(&pset)?;
|
||||||
|
let pset_balance_sat = pset_details
|
||||||
|
.balance
|
||||||
|
.balances
|
||||||
|
.get(&lwk_wollet.policy_asset())
|
||||||
|
.unwrap_or(&0);
|
||||||
|
let pset_fees = pset_details.balance.fee;
|
||||||
|
|
||||||
|
ensure_sdk!(
|
||||||
|
(*pset_balance_sat * -1) as u64 - pset_fees == enforce_amount_sat,
|
||||||
|
PaymentError::Generic {
|
||||||
|
err: format!("Drain tx amount {pset_balance_sat} sat doesn't match enforce_amount_sat {enforce_amount_sat} sat")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let signer = AnySigner::Software(self.lwk_signer.clone());
|
||||||
|
signer.sign(&mut pset)?;
|
||||||
|
Ok(lwk_wollet.finalize(&mut pset)?)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next unused address in the wallet
|
/// Get the next unused address in the wallet
|
||||||
async fn next_unused_address(&self) -> Result<Address, PaymentError> {
|
async fn next_unused_address(&self) -> Result<Address, PaymentError> {
|
||||||
Ok(self.wallet.lock().await.address(None)?.address().clone())
|
Ok(self.wallet.lock().await.address(None)?.address().clone())
|
||||||
|
|||||||
@@ -2199,6 +2199,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
return raw == null ? null : dco_decode_list_payment_type(raw);
|
return raw == null ? null : dco_decode_list_payment_type(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainAmount dco_decode_pay_onchain_amount(dynamic raw) {
|
||||||
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
|
switch (raw[0]) {
|
||||||
|
case 0:
|
||||||
|
return PayOnchainAmount_Receiver(
|
||||||
|
amountSat: dco_decode_u_64(raw[1]),
|
||||||
|
);
|
||||||
|
case 1:
|
||||||
|
return PayOnchainAmount_Drain();
|
||||||
|
default:
|
||||||
|
throw Exception("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw) {
|
PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
@@ -2376,7 +2391,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
final arr = raw as List<dynamic>;
|
final arr = raw as List<dynamic>;
|
||||||
if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}');
|
if (arr.length != 2) throw Exception('unexpected arr length: expect 2 but see ${arr.length}');
|
||||||
return PreparePayOnchainRequest(
|
return PreparePayOnchainRequest(
|
||||||
receiverAmountSat: dco_decode_u_64(arr[0]),
|
amount: dco_decode_pay_onchain_amount(arr[0]),
|
||||||
satPerVbyte: dco_decode_opt_box_autoadd_u_32(arr[1]),
|
satPerVbyte: dco_decode_opt_box_autoadd_u_32(arr[1]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -3888,6 +3903,22 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainAmount sse_decode_pay_onchain_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);
|
||||||
|
case 1:
|
||||||
|
return PayOnchainAmount_Drain();
|
||||||
|
default:
|
||||||
|
throw UnimplementedError('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer) {
|
PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -4062,9 +4093,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
@protected
|
@protected
|
||||||
PreparePayOnchainRequest sse_decode_prepare_pay_onchain_request(SseDeserializer deserializer) {
|
PreparePayOnchainRequest sse_decode_prepare_pay_onchain_request(SseDeserializer deserializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
var var_receiverAmountSat = sse_decode_u_64(deserializer);
|
var var_amount = sse_decode_pay_onchain_amount(deserializer);
|
||||||
var var_satPerVbyte = sse_decode_opt_box_autoadd_u_32(deserializer);
|
var var_satPerVbyte = sse_decode_opt_box_autoadd_u_32(deserializer);
|
||||||
return PreparePayOnchainRequest(receiverAmountSat: var_receiverAmountSat, satPerVbyte: var_satPerVbyte);
|
return PreparePayOnchainRequest(amount: var_amount, satPerVbyte: var_satPerVbyte);
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
@@ -5487,6 +5518,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_pay_onchain_amount(PayOnchainAmount self, SseSerializer serializer) {
|
||||||
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
|
switch (self) {
|
||||||
|
case PayOnchainAmount_Receiver(amountSat: final amountSat):
|
||||||
|
sse_encode_i_32(0, serializer);
|
||||||
|
sse_encode_u_64(amountSat, serializer);
|
||||||
|
case PayOnchainAmount_Drain():
|
||||||
|
sse_encode_i_32(1, serializer);
|
||||||
|
default:
|
||||||
|
throw UnimplementedError('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer) {
|
void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
@@ -5644,7 +5689,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_prepare_pay_onchain_request(PreparePayOnchainRequest self, SseSerializer serializer) {
|
void sse_encode_prepare_pay_onchain_request(PreparePayOnchainRequest self, SseSerializer serializer) {
|
||||||
// Codec=Sse (Serialization based), see doc to use other codecs
|
// Codec=Sse (Serialization based), see doc to use other codecs
|
||||||
sse_encode_u_64(self.receiverAmountSat, serializer);
|
sse_encode_pay_onchain_amount(self.amount, serializer);
|
||||||
sse_encode_opt_box_autoadd_u_32(self.satPerVbyte, serializer);
|
sse_encode_opt_box_autoadd_u_32(self.satPerVbyte, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -365,6 +365,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
List<PaymentType>? dco_decode_opt_list_payment_type(dynamic raw);
|
List<PaymentType>? dco_decode_opt_list_payment_type(dynamic raw);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainAmount dco_decode_pay_onchain_amount(dynamic raw);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw);
|
PayOnchainRequest dco_decode_pay_onchain_request(dynamic raw);
|
||||||
|
|
||||||
@@ -837,6 +840,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
List<PaymentType>? sse_decode_opt_list_payment_type(SseDeserializer deserializer);
|
List<PaymentType>? sse_decode_opt_list_payment_type(SseDeserializer deserializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
PayOnchainAmount sse_decode_pay_onchain_amount(SseDeserializer deserializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer);
|
PayOnchainRequest sse_decode_pay_onchain_request(SseDeserializer deserializer);
|
||||||
|
|
||||||
@@ -2253,6 +2259,20 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
cst_api_fill_to_wire_limits(apiObj.receive, wireObj.receive);
|
cst_api_fill_to_wire_limits(apiObj.receive, wireObj.receive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void cst_api_fill_to_wire_pay_onchain_amount(PayOnchainAmount apiObj, wire_cst_pay_onchain_amount wireObj) {
|
||||||
|
if (apiObj is PayOnchainAmount_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) {
|
||||||
|
wireObj.tag = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_pay_onchain_request(
|
void cst_api_fill_to_wire_pay_onchain_request(
|
||||||
PayOnchainRequest apiObj, wire_cst_pay_onchain_request wireObj) {
|
PayOnchainRequest apiObj, wire_cst_pay_onchain_request wireObj) {
|
||||||
@@ -2440,7 +2460,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void cst_api_fill_to_wire_prepare_pay_onchain_request(
|
void cst_api_fill_to_wire_prepare_pay_onchain_request(
|
||||||
PreparePayOnchainRequest apiObj, wire_cst_prepare_pay_onchain_request wireObj) {
|
PreparePayOnchainRequest apiObj, wire_cst_prepare_pay_onchain_request wireObj) {
|
||||||
wireObj.receiver_amount_sat = cst_encode_u_64(apiObj.receiverAmountSat);
|
cst_api_fill_to_wire_pay_onchain_amount(apiObj.amount, wireObj.amount);
|
||||||
wireObj.sat_per_vbyte = cst_encode_opt_box_autoadd_u_32(apiObj.satPerVbyte);
|
wireObj.sat_per_vbyte = cst_encode_opt_box_autoadd_u_32(apiObj.satPerVbyte);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3114,6 +3134,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
|
|||||||
@protected
|
@protected
|
||||||
void sse_encode_opt_list_payment_type(List<PaymentType>? self, SseSerializer serializer);
|
void sse_encode_opt_list_payment_type(List<PaymentType>? self, SseSerializer serializer);
|
||||||
|
|
||||||
|
@protected
|
||||||
|
void sse_encode_pay_onchain_amount(PayOnchainAmount self, SseSerializer serializer);
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer);
|
void sse_encode_pay_onchain_request(PayOnchainRequest self, SseSerializer serializer);
|
||||||
|
|
||||||
@@ -4734,9 +4757,24 @@ final class wire_cst_prepare_buy_bitcoin_request extends ffi.Struct {
|
|||||||
external int amount_sat;
|
external int amount_sat;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class wire_cst_prepare_pay_onchain_request extends ffi.Struct {
|
final class wire_cst_PayOnchainAmount_Receiver extends ffi.Struct {
|
||||||
@ffi.Uint64()
|
@ffi.Uint64()
|
||||||
external int receiver_amount_sat;
|
external int amount_sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class PayOnchainAmountKind extends ffi.Union {
|
||||||
|
external wire_cst_PayOnchainAmount_Receiver Receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_pay_onchain_amount extends ffi.Struct {
|
||||||
|
@ffi.Int32()
|
||||||
|
external int tag;
|
||||||
|
|
||||||
|
external PayOnchainAmountKind kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_prepare_pay_onchain_request extends ffi.Struct {
|
||||||
|
external wire_cst_pay_onchain_amount amount;
|
||||||
|
|
||||||
external ffi.Pointer<ffi.Uint32> sat_per_vbyte;
|
external ffi.Pointer<ffi.Uint32> sat_per_vbyte;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -405,6 +405,19 @@ class OnchainPaymentLimitsResponse {
|
|||||||
receive == other.receive;
|
receive == other.receive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class PayOnchainAmount with _$PayOnchainAmount {
|
||||||
|
const PayOnchainAmount._();
|
||||||
|
|
||||||
|
/// The amount in satoshi that will be received
|
||||||
|
const factory PayOnchainAmount.receiver({
|
||||||
|
required BigInt amountSat,
|
||||||
|
}) = PayOnchainAmount_Receiver;
|
||||||
|
|
||||||
|
/// Indicates that all available funds should be sent
|
||||||
|
const factory PayOnchainAmount.drain() = PayOnchainAmount_Drain;
|
||||||
|
}
|
||||||
|
|
||||||
/// An argument when calling [crate::sdk::LiquidSdk::pay_onchain].
|
/// An argument when calling [crate::sdk::LiquidSdk::pay_onchain].
|
||||||
class PayOnchainRequest {
|
class PayOnchainRequest {
|
||||||
final String address;
|
final String address;
|
||||||
@@ -695,23 +708,25 @@ class PrepareBuyBitcoinResponse {
|
|||||||
|
|
||||||
/// An argument when calling [crate::sdk::LiquidSdk::prepare_pay_onchain].
|
/// An argument when calling [crate::sdk::LiquidSdk::prepare_pay_onchain].
|
||||||
class PreparePayOnchainRequest {
|
class PreparePayOnchainRequest {
|
||||||
final BigInt receiverAmountSat;
|
final PayOnchainAmount amount;
|
||||||
|
|
||||||
|
/// The optional fee rate of the Bitcoin claim transaction. Defaults to the swapper estimated claim fee.
|
||||||
final int? satPerVbyte;
|
final int? satPerVbyte;
|
||||||
|
|
||||||
const PreparePayOnchainRequest({
|
const PreparePayOnchainRequest({
|
||||||
required this.receiverAmountSat,
|
required this.amount,
|
||||||
this.satPerVbyte,
|
this.satPerVbyte,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => receiverAmountSat.hashCode ^ satPerVbyte.hashCode;
|
int get hashCode => amount.hashCode ^ satPerVbyte.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is PreparePayOnchainRequest &&
|
other is PreparePayOnchainRequest &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
receiverAmountSat == other.receiverAmountSat &&
|
amount == other.amount &&
|
||||||
satPerVbyte == other.satPerVbyte;
|
satPerVbyte == other.satPerVbyte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,6 +283,153 @@ abstract class LnUrlPayResult_PayError extends LnUrlPayResult {
|
|||||||
throw _privateConstructorUsedError;
|
throw _privateConstructorUsedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$PayOnchainAmount {}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $PayOnchainAmountCopyWith<$Res> {
|
||||||
|
factory $PayOnchainAmountCopyWith(PayOnchainAmount value, $Res Function(PayOnchainAmount) then) =
|
||||||
|
_$PayOnchainAmountCopyWithImpl<$Res, PayOnchainAmount>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$PayOnchainAmountCopyWithImpl<$Res, $Val extends PayOnchainAmount>
|
||||||
|
implements $PayOnchainAmountCopyWith<$Res> {
|
||||||
|
_$PayOnchainAmountCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of PayOnchainAmount
|
||||||
|
/// 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>;
|
||||||
|
@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)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of PayOnchainAmount
|
||||||
|
/// 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(
|
||||||
|
amountSat: null == amountSat
|
||||||
|
? _value.amountSat
|
||||||
|
: amountSat // ignore: cast_nullable_to_non_nullable
|
||||||
|
as BigInt,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$PayOnchainAmount_ReceiverImpl extends PayOnchainAmount_Receiver {
|
||||||
|
const _$PayOnchainAmount_ReceiverImpl({required this.amountSat}) : super._();
|
||||||
|
|
||||||
|
@override
|
||||||
|
final BigInt amountSat;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'PayOnchainAmount.receiver(amountSat: $amountSat)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$PayOnchainAmount_ReceiverImpl &&
|
||||||
|
(identical(other.amountSat, amountSat) || other.amountSat == amountSat));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, amountSat);
|
||||||
|
|
||||||
|
/// Create a copy of PayOnchainAmount
|
||||||
|
/// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PayOnchainAmount_Receiver extends PayOnchainAmount {
|
||||||
|
const factory PayOnchainAmount_Receiver({required final BigInt amountSat}) =
|
||||||
|
_$PayOnchainAmount_ReceiverImpl;
|
||||||
|
const PayOnchainAmount_Receiver._() : super._();
|
||||||
|
|
||||||
|
BigInt get amountSat;
|
||||||
|
|
||||||
|
/// Create a copy of PayOnchainAmount
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$PayOnchainAmount_ReceiverImplCopyWith<_$PayOnchainAmount_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>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$PayOnchainAmount_DrainImplCopyWithImpl<$Res>
|
||||||
|
extends _$PayOnchainAmountCopyWithImpl<$Res, _$PayOnchainAmount_DrainImpl>
|
||||||
|
implements _$$PayOnchainAmount_DrainImplCopyWith<$Res> {
|
||||||
|
__$$PayOnchainAmount_DrainImplCopyWithImpl(
|
||||||
|
_$PayOnchainAmount_DrainImpl _value, $Res Function(_$PayOnchainAmount_DrainImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of PayOnchainAmount
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$PayOnchainAmount_DrainImpl extends PayOnchainAmount_Drain {
|
||||||
|
const _$PayOnchainAmount_DrainImpl() : super._();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'PayOnchainAmount.drain()';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType && other is _$PayOnchainAmount_DrainImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => runtimeType.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PayOnchainAmount_Drain extends PayOnchainAmount {
|
||||||
|
const factory PayOnchainAmount_Drain() = _$PayOnchainAmount_DrainImpl;
|
||||||
|
const PayOnchainAmount_Drain._() : super._();
|
||||||
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$PaymentDetails {
|
mixin _$PaymentDetails {
|
||||||
/// Represents the invoice description
|
/// Represents the invoice description
|
||||||
|
|||||||
@@ -1575,9 +1575,24 @@ final class wire_cst_prepare_buy_bitcoin_request extends ffi.Struct {
|
|||||||
external int amount_sat;
|
external int amount_sat;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class wire_cst_prepare_pay_onchain_request extends ffi.Struct {
|
final class wire_cst_PayOnchainAmount_Receiver extends ffi.Struct {
|
||||||
@ffi.Uint64()
|
@ffi.Uint64()
|
||||||
external int receiver_amount_sat;
|
external int amount_sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class PayOnchainAmountKind extends ffi.Union {
|
||||||
|
external wire_cst_PayOnchainAmount_Receiver Receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_pay_onchain_amount extends ffi.Struct {
|
||||||
|
@ffi.Int32()
|
||||||
|
external int tag;
|
||||||
|
|
||||||
|
external PayOnchainAmountKind kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
final class wire_cst_prepare_pay_onchain_request extends ffi.Struct {
|
||||||
|
external wire_cst_pay_onchain_amount amount;
|
||||||
|
|
||||||
external ffi.Pointer<ffi.Uint32> sat_per_vbyte;
|
external ffi.Pointer<ffi.Uint32> sat_per_vbyte;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1330,13 +1330,13 @@ fun asPreparePayOnchainRequest(preparePayOnchainRequest: ReadableMap): PreparePa
|
|||||||
if (!validateMandatoryFields(
|
if (!validateMandatoryFields(
|
||||||
preparePayOnchainRequest,
|
preparePayOnchainRequest,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
"receiverAmountSat",
|
"amount",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val receiverAmountSat = preparePayOnchainRequest.getDouble("receiverAmountSat").toULong()
|
val amount = preparePayOnchainRequest.getMap("amount")?.let { asPayOnchainAmount(it) }!!
|
||||||
val satPerVbyte =
|
val satPerVbyte =
|
||||||
if (hasNonNullKey(
|
if (hasNonNullKey(
|
||||||
preparePayOnchainRequest,
|
preparePayOnchainRequest,
|
||||||
@@ -1347,12 +1347,12 @@ fun asPreparePayOnchainRequest(preparePayOnchainRequest: ReadableMap): PreparePa
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
return PreparePayOnchainRequest(receiverAmountSat, satPerVbyte)
|
return PreparePayOnchainRequest(amount, satPerVbyte)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readableMapOf(preparePayOnchainRequest: PreparePayOnchainRequest): ReadableMap =
|
fun readableMapOf(preparePayOnchainRequest: PreparePayOnchainRequest): ReadableMap =
|
||||||
readableMapOf(
|
readableMapOf(
|
||||||
"receiverAmountSat" to preparePayOnchainRequest.receiverAmountSat,
|
"amount" to readableMapOf(preparePayOnchainRequest.amount),
|
||||||
"satPerVbyte" to preparePayOnchainRequest.satPerVbyte,
|
"satPerVbyte" to preparePayOnchainRequest.satPerVbyte,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2485,6 +2485,44 @@ fun asNetworkList(arr: ReadableArray): List<Network> {
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asPayOnchainAmount(payOnchainAmount: ReadableMap): PayOnchainAmount? {
|
||||||
|
val type = payOnchainAmount.getString("type")
|
||||||
|
|
||||||
|
if (type == "receiver") {
|
||||||
|
val amountSat = payOnchainAmount.getDouble("amountSat").toULong()
|
||||||
|
return PayOnchainAmount.Receiver(amountSat)
|
||||||
|
}
|
||||||
|
if (type == "drain") {
|
||||||
|
return PayOnchainAmount.Drain
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readableMapOf(payOnchainAmount: PayOnchainAmount): ReadableMap? {
|
||||||
|
val map = Arguments.createMap()
|
||||||
|
when (payOnchainAmount) {
|
||||||
|
is PayOnchainAmount.Receiver -> {
|
||||||
|
pushToMap(map, "type", "receiver")
|
||||||
|
pushToMap(map, "amountSat", payOnchainAmount.amountSat)
|
||||||
|
}
|
||||||
|
is PayOnchainAmount.Drain -> {
|
||||||
|
pushToMap(map, "type", "drain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
fun asPayOnchainAmountList(arr: ReadableArray): List<PayOnchainAmount> {
|
||||||
|
val list = ArrayList<PayOnchainAmount>()
|
||||||
|
for (value in arr.toList()) {
|
||||||
|
when (value) {
|
||||||
|
is ReadableMap -> list.add(asPayOnchainAmount(value)!!)
|
||||||
|
else -> throw SdkException.Generic(errUnexpectedType(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
fun asPaymentDetails(paymentDetails: ReadableMap): PaymentDetails? {
|
fun asPaymentDetails(paymentDetails: ReadableMap): PaymentDetails? {
|
||||||
val type = paymentDetails.getString("type")
|
val type = paymentDetails.getString("type")
|
||||||
|
|
||||||
|
|||||||
@@ -1571,9 +1571,11 @@ enum BreezSDKLiquidMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static func asPreparePayOnchainRequest(preparePayOnchainRequest: [String: Any?]) throws -> PreparePayOnchainRequest {
|
static func asPreparePayOnchainRequest(preparePayOnchainRequest: [String: Any?]) throws -> PreparePayOnchainRequest {
|
||||||
guard let receiverAmountSat = preparePayOnchainRequest["receiverAmountSat"] as? UInt64 else {
|
guard let amountTmp = preparePayOnchainRequest["amount"] as? [String: Any?] else {
|
||||||
throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "receiverAmountSat", typeName: "PreparePayOnchainRequest"))
|
throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "amount", typeName: "PreparePayOnchainRequest"))
|
||||||
}
|
}
|
||||||
|
let amount = try asPayOnchainAmount(payOnchainAmount: amountTmp)
|
||||||
|
|
||||||
var satPerVbyte: UInt32?
|
var satPerVbyte: UInt32?
|
||||||
if hasNonNilKey(data: preparePayOnchainRequest, key: "satPerVbyte") {
|
if hasNonNilKey(data: preparePayOnchainRequest, key: "satPerVbyte") {
|
||||||
guard let satPerVbyteTmp = preparePayOnchainRequest["satPerVbyte"] as? UInt32 else {
|
guard let satPerVbyteTmp = preparePayOnchainRequest["satPerVbyte"] as? UInt32 else {
|
||||||
@@ -1582,12 +1584,12 @@ enum BreezSDKLiquidMapper {
|
|||||||
satPerVbyte = satPerVbyteTmp
|
satPerVbyte = satPerVbyteTmp
|
||||||
}
|
}
|
||||||
|
|
||||||
return PreparePayOnchainRequest(receiverAmountSat: receiverAmountSat, satPerVbyte: satPerVbyte)
|
return PreparePayOnchainRequest(amount: amount, satPerVbyte: satPerVbyte)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func dictionaryOf(preparePayOnchainRequest: PreparePayOnchainRequest) -> [String: Any?] {
|
static func dictionaryOf(preparePayOnchainRequest: PreparePayOnchainRequest) -> [String: Any?] {
|
||||||
return [
|
return [
|
||||||
"receiverAmountSat": preparePayOnchainRequest.receiverAmountSat,
|
"amount": dictionaryOf(payOnchainAmount: preparePayOnchainRequest.amount),
|
||||||
"satPerVbyte": preparePayOnchainRequest.satPerVbyte == nil ? nil : preparePayOnchainRequest.satPerVbyte,
|
"satPerVbyte": preparePayOnchainRequest.satPerVbyte == nil ? nil : preparePayOnchainRequest.satPerVbyte,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -3065,6 +3067,55 @@ enum BreezSDKLiquidMapper {
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func asPayOnchainAmount(payOnchainAmount: [String: Any?]) throws -> PayOnchainAmount {
|
||||||
|
let type = payOnchainAmount["type"] as! String
|
||||||
|
if type == "receiver" {
|
||||||
|
guard let _amountSat = payOnchainAmount["amountSat"] as? UInt64 else {
|
||||||
|
throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "amountSat", typeName: "PayOnchainAmount"))
|
||||||
|
}
|
||||||
|
return PayOnchainAmount.receiver(amountSat: _amountSat)
|
||||||
|
}
|
||||||
|
if type == "drain" {
|
||||||
|
return PayOnchainAmount.drain
|
||||||
|
}
|
||||||
|
|
||||||
|
throw SdkError.Generic(message: "Unexpected type \(type) for enum PayOnchainAmount")
|
||||||
|
}
|
||||||
|
|
||||||
|
static func dictionaryOf(payOnchainAmount: PayOnchainAmount) -> [String: Any?] {
|
||||||
|
switch payOnchainAmount {
|
||||||
|
case let .receiver(
|
||||||
|
amountSat
|
||||||
|
):
|
||||||
|
return [
|
||||||
|
"type": "receiver",
|
||||||
|
"amountSat": amountSat,
|
||||||
|
]
|
||||||
|
|
||||||
|
case .drain:
|
||||||
|
return [
|
||||||
|
"type": "drain",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func arrayOf(payOnchainAmountList: [PayOnchainAmount]) -> [Any] {
|
||||||
|
return payOnchainAmountList.map { v -> [String: Any?] in return dictionaryOf(payOnchainAmount: v) }
|
||||||
|
}
|
||||||
|
|
||||||
|
static func asPayOnchainAmountList(arr: [Any]) throws -> [PayOnchainAmount] {
|
||||||
|
var list = [PayOnchainAmount]()
|
||||||
|
for value in arr {
|
||||||
|
if let val = value as? [String: Any?] {
|
||||||
|
var payOnchainAmount = try asPayOnchainAmount(payOnchainAmount: val)
|
||||||
|
list.append(payOnchainAmount)
|
||||||
|
} else {
|
||||||
|
throw SdkError.Generic(message: errUnexpectedType(typeName: "PayOnchainAmount"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
static func asPaymentDetails(paymentDetails: [String: Any?]) throws -> PaymentDetails {
|
static func asPaymentDetails(paymentDetails: [String: Any?]) throws -> PaymentDetails {
|
||||||
let type = paymentDetails["type"] as! String
|
let type = paymentDetails["type"] as! String
|
||||||
if type == "lightning" {
|
if type == "lightning" {
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ export interface PrepareBuyBitcoinResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PreparePayOnchainRequest {
|
export interface PreparePayOnchainRequest {
|
||||||
receiverAmountSat: number
|
amount: PayOnchainAmount
|
||||||
satPerVbyte?: number
|
satPerVbyte?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,6 +489,18 @@ export enum Network {
|
|||||||
REGTEST = "regtest"
|
REGTEST = "regtest"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PayOnchainAmountVariant {
|
||||||
|
RECEIVER = "receiver",
|
||||||
|
DRAIN = "drain"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PayOnchainAmount = {
|
||||||
|
type: PayOnchainAmountVariant.RECEIVER,
|
||||||
|
amountSat: number
|
||||||
|
} | {
|
||||||
|
type: PayOnchainAmountVariant.DRAIN
|
||||||
|
}
|
||||||
|
|
||||||
export enum PaymentDetailsVariant {
|
export enum PaymentDetailsVariant {
|
||||||
LIGHTNING = "lightning",
|
LIGHTNING = "lightning",
|
||||||
LIQUID = "liquid",
|
LIQUID = "liquid",
|
||||||
|
|||||||
Reference in New Issue
Block a user