Store actual payer and accepted receiver amounts

This commit is contained in:
Daniel Granhão
2024-12-30 13:56:01 +00:00
parent d2be2ea49a
commit a1e5576286
14 changed files with 217 additions and 74 deletions

View File

@@ -65,6 +65,8 @@ typedef void (*UniFfiRustFutureContinuation)(void * _Nonnull, int8_t);
// Scaffolding functions // Scaffolding functions
void uniffi_breez_sdk_liquid_bindings_fn_free_bindingliquidsdk(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status void uniffi_breez_sdk_liquid_bindings_fn_free_bindingliquidsdk(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status
); );
void uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_fees(void*_Nonnull ptr, RustBuffer req, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_add_event_listener(void*_Nonnull ptr, uint64_t listener, RustCallStatus *_Nonnull out_status RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_add_event_listener(void*_Nonnull ptr, uint64_t listener, RustCallStatus *_Nonnull out_status
); );
void uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_backup(void*_Nonnull ptr, RustBuffer req, RustCallStatus *_Nonnull out_status void uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_backup(void*_Nonnull ptr, RustBuffer req, RustCallStatus *_Nonnull out_status
@@ -81,6 +83,8 @@ RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_lig
); );
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_onchain_limits(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_onchain_limits(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status
); );
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_fees(void*_Nonnull ptr, RustBuffer req, RustCallStatus *_Nonnull out_status
);
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_get_info(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_get_info(void*_Nonnull ptr, RustCallStatus *_Nonnull out_status
); );
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_get_payment(void*_Nonnull ptr, RustBuffer req, RustCallStatus *_Nonnull out_status RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_get_payment(void*_Nonnull ptr, RustBuffer req, RustCallStatus *_Nonnull out_status
@@ -279,6 +283,9 @@ uint16_t uniffi_breez_sdk_liquid_bindings_checksum_func_parse_invoice(void
); );
uint16_t uniffi_breez_sdk_liquid_bindings_checksum_func_set_logger(void uint16_t uniffi_breez_sdk_liquid_bindings_checksum_func_set_logger(void
);
uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_fees(void
); );
uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_add_event_listener(void uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_add_event_listener(void
@@ -303,6 +310,9 @@ uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch
); );
uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_onchain_limits(void uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_onchain_limits(void
);
uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_fees(void
); );
uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_get_info(void uint16_t uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_get_info(void

View File

@@ -101,12 +101,9 @@ impl ChainSwapHandler {
.map_err(|_| anyhow!("Invalid ChainSwapState for Chain Swap {id}: {status}"))?; .map_err(|_| anyhow!("Invalid ChainSwapState for Chain Swap {id}: {status}"))?;
match swap_state { match swap_state {
// If the swap is not local (pulled from real-time sync) we do not: // If the swap is not local (pulled from real-time sync) we do not claim twice
// - claim twice
// - accept fees twice
ChainSwapStates::TransactionServerMempool ChainSwapStates::TransactionServerMempool
| ChainSwapStates::TransactionServerConfirmed | ChainSwapStates::TransactionServerConfirmed => {
| ChainSwapStates::TransactionLockupFailed => {
log::debug!("Received {swap_state:?} for non-local Chain swap {id} from status stream, skipping update."); log::debug!("Received {swap_state:?} for non-local Chain swap {id} from status stream, skipping update.");
return Ok(()); return Ok(());
} }
@@ -331,7 +328,7 @@ impl ChainSwapHandler {
| ChainSwapStates::TransactionRefunded | ChainSwapStates::TransactionRefunded
| ChainSwapStates::SwapExpired => { | ChainSwapStates::SwapExpired => {
// Zero-amount Receive Chain Swaps also get to TransactionLockupFailed when user locks up funds // Zero-amount Receive Chain Swaps also get to TransactionLockupFailed when user locks up funds
let is_zero_amount = swap.get_boltz_create_response()?.lockup_details.amount == 0; let is_zero_amount = swap.payer_amount_sat == 0;
if matches!(swap_state, ChainSwapStates::TransactionLockupFailed) && is_zero_amount if matches!(swap_state, ChainSwapStates::TransactionLockupFailed) && is_zero_amount
{ {
match self.handle_amountless_update(swap).await { match self.handle_amountless_update(swap).await {
@@ -395,26 +392,19 @@ impl ChainSwapHandler {
receiver_amount_sat, receiver_amount_sat,
} => { } => {
debug!("Zero-amount swap validated. Auto-accepting..."); debug!("Zero-amount swap validated. Auto-accepting...");
self.persister.update_zero_amount_swap_values( self.persister
&id, .update_actual_payer_amount(&id, user_lockup_amount_sat)?;
user_lockup_amount_sat,
receiver_amount_sat,
)?;
self.swapper self.swapper
.accept_zero_amount_chain_swap_quote(&id, quote) .accept_zero_amount_chain_swap_quote(&id, quote)?;
.map_err(Into::into) self.persister
.update_accepted_receiver_amount(&id, receiver_amount_sat)
} }
ValidateAmountlessSwapResult::RequiresUserAction { ValidateAmountlessSwapResult::RequiresUserAction {
user_lockup_amount_sat, user_lockup_amount_sat,
receiver_amount_sat_original_estimate,
} => { } => {
debug!("Zero-amount swap validated. Fees are too high for automatic accepting. Moving to WaitingFeeAcceptance"); debug!("Zero-amount swap validated. Fees are too high for automatic accepting. Moving to WaitingFeeAcceptance");
// While the user doesn't accept new fees, let's continue to show the original estimate self.persister
self.persister.update_zero_amount_swap_values( .update_actual_payer_amount(&id, user_lockup_amount_sat)?;
&id,
user_lockup_amount_sat,
receiver_amount_sat_original_estimate,
)?;
self.update_swap_info(&ChainSwapUpdate { self.update_swap_info(&ChainSwapUpdate {
swap_id: id, swap_id: id,
to_state: WaitingFeeAcceptance, to_state: WaitingFeeAcceptance,
@@ -486,11 +476,8 @@ impl ChainSwapHandler {
); );
if min_auto_accept_server_lockup_amount_sat > quote_server_lockup_amount_sat { if min_auto_accept_server_lockup_amount_sat > quote_server_lockup_amount_sat {
let receiver_amount_sat_original_estimate =
server_lockup_amount_estimate_sat - swap.claim_fees_sat;
Ok(ValidateAmountlessSwapResult::RequiresUserAction { Ok(ValidateAmountlessSwapResult::RequiresUserAction {
user_lockup_amount_sat, user_lockup_amount_sat,
receiver_amount_sat_original_estimate,
}) })
} else { } else {
let receiver_amount_sat = quote_server_lockup_amount_sat - swap.claim_fees_sat; let receiver_amount_sat = quote_server_lockup_amount_sat - swap.claim_fees_sat;
@@ -1233,12 +1220,25 @@ impl ChainSwapHandler {
.unblind(&secp, liquid_swap_script.blinding_key.secret_key())? .unblind(&secp, liquid_swap_script.blinding_key.secret_key())?
.value; .value;
} }
match chain_swap.accepted_receiver_amount_sat {
None => {
if value < claim_details.amount { if value < claim_details.amount {
return Err(anyhow!( return Err(anyhow!(
"Transaction value {value} sats is less than {} sats", "Transaction value {value} sats is less than {} sats",
claim_details.amount claim_details.amount
)); ));
} }
}
Some(accepted_receiver_amount_sat) => {
if value < accepted_receiver_amount_sat - chain_swap.claim_fees_sat {
return Err(anyhow!(
"Transaction value {value} sats is less than accepted {} sats",
claim_details.amount
));
}
}
}
Ok(()) Ok(())
} }
@@ -1362,7 +1362,6 @@ enum ValidateAmountlessSwapResult {
}, },
RequiresUserAction { RequiresUserAction {
user_lockup_amount_sat: u64, user_lockup_amount_sat: u64,
receiver_amount_sat_original_estimate: u64,
}, },
} }

View File

@@ -729,8 +729,14 @@ pub(crate) struct ChainSwap {
pub(crate) timeout_block_height: u32, pub(crate) timeout_block_height: u32,
pub(crate) preimage: String, pub(crate) preimage: String,
pub(crate) description: Option<String>, pub(crate) description: Option<String>,
/// Payer amount defined at swap creation
pub(crate) payer_amount_sat: u64, pub(crate) payer_amount_sat: u64,
/// The actual payer amount in case it differs from `payer_amount_sat` (over/underpayment)
pub(crate) actual_payer_amount_sat: Option<u64>,
/// Receiver amount defined at swap creation
pub(crate) receiver_amount_sat: u64, pub(crate) receiver_amount_sat: u64,
/// The final receiver amount, in case of an over/underpayment that has been accepted
pub(crate) accepted_receiver_amount_sat: Option<u64>,
pub(crate) claim_fees_sat: u64, pub(crate) claim_fees_sat: u64,
/// The [ChainPair] chosen on swap creation /// The [ChainPair] chosen on swap creation
pub(crate) pair_fees_json: String, pub(crate) pair_fees_json: String,

View File

@@ -147,7 +147,9 @@ impl Persister {
refund_tx_id, refund_tx_id,
created_at, created_at,
state, state,
pair_fees_json pair_fees_json,
actual_payer_amount_sat,
accepted_receiver_amount_sat
FROM chain_swaps FROM chain_swaps
{where_clause_str} {where_clause_str}
ORDER BY created_at ORDER BY created_at
@@ -197,6 +199,8 @@ impl Persister {
created_at: row.get(18)?, created_at: row.get(18)?,
state: row.get(19)?, state: row.get(19)?,
pair_fees_json: row.get(20)?, pair_fees_json: row.get(20)?,
actual_payer_amount_sat: row.get(21)?,
accepted_receiver_amount_sat: row.get(22)?,
}) })
} }
@@ -286,39 +290,55 @@ impl Persister {
Ok(()) Ok(())
} }
/// Used for Zero-amount Receive Chain swaps, when we fetched the quote and we know how much /// Used for receive chain swaps, when the sender over/underpays
/// the sender locked up pub(crate) fn update_actual_payer_amount(
pub(crate) fn update_zero_amount_swap_values(
&self, &self,
swap_id: &str, swap_id: &str,
payer_amount_sat: u64, actual_payer_amount_sat: u64,
receiver_amount_sat: u64,
) -> Result<(), PaymentError> { ) -> Result<(), PaymentError> {
log::info!("Updating chain swap {swap_id}: payer_amount_sat = {payer_amount_sat}, receiver_amount_sat = {receiver_amount_sat}"); log::info!(
"Updating chain swap {swap_id}: actual_payer_amount_sat = {actual_payer_amount_sat}"
);
let con: Connection = self.get_connection()?;
con.execute(
"UPDATE chain_swaps
SET actual_payer_amount_sat = :actual_payer_amount_sat
WHERE id = :id",
named_params! {
":id": swap_id,
":actual_payer_amount_sat": actual_payer_amount_sat,
},
)?;
Ok(())
}
/// Used for receive chain swaps, when fees are accepted and thus the agreed received amount is known
pub(crate) fn update_accepted_receiver_amount(
&self,
swap_id: &str,
accepted_receiver_amount_sat: u64,
) -> Result<(), PaymentError> {
log::info!(
"Updating chain swap {swap_id}: accepted_receiver_amount_sat = {accepted_receiver_amount_sat}"
);
let mut con: Connection = self.get_connection()?; let mut con: Connection = self.get_connection()?;
let tx = con.transaction_with_behavior(TransactionBehavior::Immediate)?; let tx = con.transaction_with_behavior(TransactionBehavior::Immediate)?;
tx.execute( tx.execute(
"UPDATE chain_swaps "UPDATE chain_swaps
SET SET accepted_receiver_amount_sat = :accepted_receiver_amount_sat
payer_amount_sat = :payer_amount_sat, WHERE id = :id",
receiver_amount_sat = :receiver_amount_sat
WHERE
id = :id",
named_params! { named_params! {
":id": swap_id, ":id": swap_id,
":payer_amount_sat": payer_amount_sat, ":accepted_receiver_amount_sat": accepted_receiver_amount_sat,
":receiver_amount_sat": receiver_amount_sat,
}, },
)?; )?;
self.commit_outgoing( self.commit_outgoing(
&tx, &tx,
swap_id, swap_id,
RecordType::Chain, RecordType::Chain,
Some(vec![ Some(vec!["accepted_receiver_amount_sat".to_string()]),
"payer_amount_sat".to_string(),
"receiver_amount_sat".to_string(),
]),
)?; )?;
tx.commit()?; tx.commit()?;
self.sync_trigger self.sync_trigger

View File

@@ -215,5 +215,7 @@ pub(crate) fn current_migrations() -> Vec<&'static str> {
"ALTER TABLE receive_swaps DROP COLUMN mrh_script_pubkey;", "ALTER TABLE receive_swaps DROP COLUMN mrh_script_pubkey;",
"ALTER TABLE payment_details ADD COLUMN lnurl_info_json TEXT;", "ALTER TABLE payment_details ADD COLUMN lnurl_info_json TEXT;",
"ALTER TABLE payment_tx_data ADD COLUMN unblinding_data TEXT;", "ALTER TABLE payment_tx_data ADD COLUMN unblinding_data TEXT;",
"ALTER TABLE chain_swaps ADD COLUMN actual_payer_amount_sat INTEGER;",
"ALTER TABLE chain_swaps ADD COLUMN accepted_receiver_amount_sat INTEGER;",
] ]
} }

View File

@@ -400,6 +400,8 @@ impl Persister {
cs.claim_address, cs.claim_address,
cs.state, cs.state,
cs.pair_fees_json, cs.pair_fees_json,
cs.actual_payer_amount_sat,
cs.accepted_receiver_amount_sat,
rtx.amount_sat, rtx.amount_sat,
pd.destination, pd.destination,
pd.description, pd.description,
@@ -497,12 +499,14 @@ impl Persister {
let maybe_chain_swap_pair_fees_json: Option<String> = row.get(39)?; let maybe_chain_swap_pair_fees_json: Option<String> = row.get(39)?;
let maybe_chain_swap_pair_fees: Option<ChainPair> = let maybe_chain_swap_pair_fees: Option<ChainPair> =
maybe_chain_swap_pair_fees_json.and_then(|pair| serde_json::from_str(&pair).ok()); maybe_chain_swap_pair_fees_json.and_then(|pair| serde_json::from_str(&pair).ok());
let maybe_chain_swap_actual_payer_amount_sat: Option<u64> = row.get(40)?;
let maybe_chain_swap_accepted_receiver_amount_sat: Option<u64> = row.get(41)?;
let maybe_swap_refund_tx_amount_sat: Option<u64> = row.get(40)?; let maybe_swap_refund_tx_amount_sat: Option<u64> = row.get(42)?;
let maybe_payment_details_destination: Option<String> = row.get(41)?; let maybe_payment_details_destination: Option<String> = row.get(43)?;
let maybe_payment_details_description: Option<String> = row.get(42)?; let maybe_payment_details_description: Option<String> = row.get(44)?;
let maybe_payment_details_lnurl_info_json: Option<String> = row.get(43)?; let maybe_payment_details_lnurl_info_json: Option<String> = row.get(45)?;
let maybe_payment_details_lnurl_info: Option<LnUrlInfo> = let maybe_payment_details_lnurl_info: Option<LnUrlInfo> =
maybe_payment_details_lnurl_info_json.and_then(|info| serde_json::from_str(&info).ok()); maybe_payment_details_lnurl_info_json.and_then(|info| serde_json::from_str(&info).ok());
@@ -569,7 +573,18 @@ impl Persister {
} }
None => match maybe_chain_swap_id { None => match maybe_chain_swap_id {
Some(chain_swap_id) => { Some(chain_swap_id) => {
let payer_amount_sat = maybe_chain_swap_payer_amount_sat.unwrap_or(0); let payer_amount_sat = match maybe_chain_swap_actual_payer_amount_sat {
Some(actual_payer_amount_sat) => actual_payer_amount_sat,
None => maybe_chain_swap_payer_amount_sat.unwrap_or(0),
};
let receiver_amount_sat =
match maybe_chain_swap_accepted_receiver_amount_sat {
Some(accepted_receiver_amount_sat) => accepted_receiver_amount_sat,
None => match maybe_chain_swap_actual_payer_amount_sat {
Some(_) => payer_amount_sat, // For over/underpaid chain swaps WaitingFeeAcceptance, show zero fees
None => maybe_chain_swap_receiver_amount_sat.unwrap_or(0),
},
};
let swapper_fees_sat = maybe_chain_swap_pair_fees let swapper_fees_sat = maybe_chain_swap_pair_fees
.map(|pair| pair.fees.percentage) .map(|pair| pair.fees.percentage)
.map(|fr| ((fr / 100.0) * payer_amount_sat as f64).ceil() as u64) .map(|fr| ((fr / 100.0) * payer_amount_sat as f64).ceil() as u64)
@@ -587,8 +602,7 @@ impl Persister {
description: maybe_chain_swap_description description: maybe_chain_swap_description
.unwrap_or("Bitcoin transfer".to_string()), .unwrap_or("Bitcoin transfer".to_string()),
payer_amount_sat, payer_amount_sat,
receiver_amount_sat: maybe_chain_swap_receiver_amount_sat receiver_amount_sat,
.unwrap_or(0),
swapper_fees_sat, swapper_fees_sat,
refund_tx_id: maybe_chain_swap_refund_tx_id, refund_tx_id: maybe_chain_swap_refund_tx_id,
refund_tx_amount_sat: maybe_swap_refund_tx_amount_sat, refund_tx_amount_sat: maybe_swap_refund_tx_amount_sat,

View File

@@ -199,6 +199,7 @@ impl RecoveredOnchainDataChainReceive {
&self, &self,
min_lockup_amount_sat: u64, min_lockup_amount_sat: u64,
is_expired: bool, is_expired: bool,
is_waiting_fee_acceptance: bool,
) -> Option<PaymentState> { ) -> Option<PaymentState> {
let is_refundable = self.btc_user_lockup_amount_sat > 0 let is_refundable = self.btc_user_lockup_amount_sat > 0
&& (is_expired || self.btc_user_lockup_amount_sat < min_lockup_amount_sat); && (is_expired || self.btc_user_lockup_amount_sat < min_lockup_amount_sat);
@@ -232,9 +233,12 @@ impl RecoveredOnchainDataChainReceive {
} }
(None, None) => match is_refundable { (None, None) => match is_refundable {
true => Some(PaymentState::Refundable), true => Some(PaymentState::Refundable),
false => match is_waiting_fee_acceptance {
true => Some(PaymentState::WaitingFeeAcceptance),
false => Some(PaymentState::Pending), false => Some(PaymentState::Pending),
}, },
}, },
},
None => match is_expired { None => match is_expired {
true => Some(PaymentState::Failed), true => Some(PaymentState::Failed),
// We have no onchain data to support deriving the state as the swap could // We have no onchain data to support deriving the state as the swap could

View File

@@ -13,7 +13,6 @@ use lwk_wollet::WalletTx;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use super::model::*; use super::model::*;
use crate::model::PaymentState;
use crate::prelude::{Direction, Swap}; use crate::prelude::{Direction, Swap};
use crate::wallet::OnchainWallet; use crate::wallet::OnchainWallet;
use crate::{ use crate::{
@@ -213,18 +212,24 @@ impl Recoverer {
log::warn!("Could not apply recovered data for incoming Chain swap {swap_id}: recovery data not found"); log::warn!("Could not apply recovered data for incoming Chain swap {swap_id}: recovery data not found");
continue; continue;
}; };
if chain_swap.receiver_amount_sat
!= recovered_data.btc_user_lockup_amount_sat
{
chain_swap.actual_payer_amount_sat =
Some(recovered_data.btc_user_lockup_amount_sat)
}
let is_expired = bitcoin_height >= chain_swap.timeout_block_height; let is_expired = bitcoin_height >= chain_swap.timeout_block_height;
let min_lockup_amount_sat = chain_swap.payer_amount_sat; let min_lockup_amount_sat = chain_swap.payer_amount_sat;
let is_waiting_fee_acceptance = let is_waiting_fee_acceptance =
chain_swap.state == PaymentState::WaitingFeeAcceptance; chain_swap.actual_payer_amount_sat.is_some()
if let Some(new_state) = && chain_swap.accepted_receiver_amount_sat.is_none();
recovered_data.derive_partial_state(min_lockup_amount_sat, is_expired) if let Some(new_state) = recovered_data.derive_partial_state(
{ min_lockup_amount_sat,
// When local state is WaitingFeeAcceptance do not change to Pending is_expired,
if !(new_state == PaymentState::Pending && is_waiting_fee_acceptance) { is_waiting_fee_acceptance,
) {
chain_swap.state = new_state; chain_swap.state = new_state;
} }
}
chain_swap.server_lockup_tx_id = recovered_data chain_swap.server_lockup_tx_id = recovered_data
.lbtc_server_lockup_tx_id .lbtc_server_lockup_tx_id
.clone() .clone()

View File

@@ -1644,7 +1644,9 @@ impl LiquidSdk {
preimage: preimage_str, preimage: preimage_str,
description: Some("Bitcoin transfer".to_string()), description: Some("Bitcoin transfer".to_string()),
payer_amount_sat, payer_amount_sat,
actual_payer_amount_sat: None,
receiver_amount_sat, receiver_amount_sat,
accepted_receiver_amount_sat: None,
claim_fees_sat, claim_fees_sat,
pair_fees_json: serde_json::to_string(&pair).map_err(|e| { pair_fees_json: serde_json::to_string(&pair).map_err(|e| {
PaymentError::generic(&format!("Failed to serialize outgoing ChainPair: {e:?}")) PaymentError::generic(&format!("Failed to serialize outgoing ChainPair: {e:?}"))
@@ -2086,7 +2088,9 @@ impl LiquidSdk {
preimage: preimage_str, preimage: preimage_str,
description: Some("Bitcoin transfer".to_string()), description: Some("Bitcoin transfer".to_string()),
payer_amount_sat: user_lockup_amount_sat.unwrap_or(0), payer_amount_sat: user_lockup_amount_sat.unwrap_or(0),
actual_payer_amount_sat: None,
receiver_amount_sat, receiver_amount_sat,
accepted_receiver_amount_sat: None,
claim_fees_sat, claim_fees_sat,
pair_fees_json: serde_json::to_string(&pair).map_err(|e| { pair_fees_json: serde_json::to_string(&pair).map_err(|e| {
PaymentError::generic(&format!("Failed to serialize incoming ChainPair: {e:?}")) PaymentError::generic(&format!("Failed to serialize incoming ChainPair: {e:?}"))
@@ -2596,13 +2600,20 @@ impl LiquidSdk {
.swapper .swapper
.get_zero_amount_chain_swap_quote(&req.swap_id)?; .get_zero_amount_chain_swap_quote(&req.swap_id)?;
let payer_amount_sat = chain_swap.payer_amount_sat; let actual_payer_amount_sat =
let fees_sat = payer_amount_sat - server_lockup_quote.to_sat() + chain_swap.claim_fees_sat; chain_swap
.actual_payer_amount_sat
.ok_or(SdkError::Generic {
err: "No actual payer amount found when state is WaitingFeeAcceptance"
.to_string(),
})?;
let fees_sat =
actual_payer_amount_sat - server_lockup_quote.to_sat() + chain_swap.claim_fees_sat;
Ok(FetchPaymentProposedFeesResponse { Ok(FetchPaymentProposedFeesResponse {
swap_id: req.swap_id.clone(), swap_id: req.swap_id.clone(),
fees_sat, fees_sat,
payer_amount_sat, payer_amount_sat: actual_payer_amount_sat,
}) })
} }
@@ -2640,13 +2651,10 @@ impl LiquidSdk {
PaymentError::InvalidOrExpiredFees PaymentError::InvalidOrExpiredFees
); );
self.persister.update_zero_amount_swap_values(
&swap_id,
payer_amount_sat,
payer_amount_sat - fees_sat,
)?;
self.swapper self.swapper
.accept_zero_amount_chain_swap_quote(&swap_id, server_lockup_quote.to_sat())?; .accept_zero_amount_chain_swap_quote(&swap_id, server_lockup_quote.to_sat())?;
self.persister
.update_accepted_receiver_amount(&swap_id, payer_amount_sat - fees_sat)?;
self.chain_swap_handler.update_swap_info(&ChainSwapUpdate { self.chain_swap_handler.update_swap_info(&ChainSwapUpdate {
swap_id, swap_id,
to_state: Pending, to_state: Pending,

View File

@@ -21,6 +21,7 @@ pub(crate) struct ChainSyncData {
pub(crate) timeout_block_height: u32, pub(crate) timeout_block_height: u32,
pub(crate) payer_amount_sat: u64, pub(crate) payer_amount_sat: u64,
pub(crate) receiver_amount_sat: u64, pub(crate) receiver_amount_sat: u64,
pub(crate) accepted_receiver_amount_sat: Option<u64>,
pub(crate) accept_zero_conf: bool, pub(crate) accept_zero_conf: bool,
pub(crate) created_at: u32, pub(crate) created_at: u32,
pub(crate) description: Option<String>, pub(crate) description: Option<String>,
@@ -68,6 +69,7 @@ impl From<ChainSwap> for ChainSyncData {
timeout_block_height: value.timeout_block_height, timeout_block_height: value.timeout_block_height,
payer_amount_sat: value.payer_amount_sat, payer_amount_sat: value.payer_amount_sat,
receiver_amount_sat: value.receiver_amount_sat, receiver_amount_sat: value.receiver_amount_sat,
accepted_receiver_amount_sat: value.accepted_receiver_amount_sat,
accept_zero_conf: value.accept_zero_conf, accept_zero_conf: value.accept_zero_conf,
created_at: value.created_at, created_at: value.created_at,
description: value.description, description: value.description,
@@ -85,7 +87,9 @@ impl From<ChainSyncData> for ChainSwap {
preimage: val.preimage, preimage: val.preimage,
description: val.description, description: val.description,
payer_amount_sat: val.payer_amount_sat, payer_amount_sat: val.payer_amount_sat,
actual_payer_amount_sat: None,
receiver_amount_sat: val.receiver_amount_sat, receiver_amount_sat: val.receiver_amount_sat,
accepted_receiver_amount_sat: val.accepted_receiver_amount_sat,
claim_fees_sat: val.claim_fees_sat, claim_fees_sat: val.claim_fees_sat,
accept_zero_conf: val.accept_zero_conf, accept_zero_conf: val.accept_zero_conf,
pair_fees_json: val.pair_fees_json, pair_fees_json: val.pair_fees_json,

View File

@@ -18,7 +18,7 @@ pub(crate) mod sync;
const MESSAGE_PREFIX: &[u8; 13] = b"realtimesync:"; const MESSAGE_PREFIX: &[u8; 13] = b"realtimesync:";
lazy_static! { lazy_static! {
static ref CURRENT_SCHEMA_VERSION: Version = Version::parse("0.0.1").unwrap(); static ref CURRENT_SCHEMA_VERSION: Version = Version::parse("0.0.2").unwrap();
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]

View File

@@ -106,7 +106,9 @@ pub(crate) fn new_chain_swap(
refund_private_key: "9e23d322577cfeb2b5490f3f86db58c806004afcb7c88995927bfdfc1c64cd8c" refund_private_key: "9e23d322577cfeb2b5490f3f86db58c806004afcb7c88995927bfdfc1c64cd8c"
.to_string(), .to_string(),
payer_amount_sat: 0, payer_amount_sat: 0,
actual_payer_amount_sat: None,
receiver_amount_sat: 0, receiver_amount_sat: 0,
accepted_receiver_amount_sat: None,
claim_fees_sat: 144, claim_fees_sat: 144,
server_lockup_tx_id: None, server_lockup_tx_id: None,
user_lockup_tx_id, user_lockup_tx_id,
@@ -191,7 +193,9 @@ pub(crate) fn new_chain_swap(
claim_private_key: "4b04c3b95570fc48c7f33bc900b801245c2be31b90d41616477574aedc5b9d28".to_string(), claim_private_key: "4b04c3b95570fc48c7f33bc900b801245c2be31b90d41616477574aedc5b9d28".to_string(),
refund_private_key: "9e23d322577cfeb2b5490f3f86db58c806004afcb7c88995927bfdfc1c64cd8c".to_string(), refund_private_key: "9e23d322577cfeb2b5490f3f86db58c806004afcb7c88995927bfdfc1c64cd8c".to_string(),
payer_amount_sat: 18360, payer_amount_sat: 18360,
actual_payer_amount_sat: None,
receiver_amount_sat: 17592, receiver_amount_sat: 17592,
accepted_receiver_amount_sat: None,
claim_fees_sat: 144, claim_fees_sat: 144,
server_lockup_tx_id: None, server_lockup_tx_id: None,
user_lockup_tx_id, user_lockup_tx_id,
@@ -273,7 +277,9 @@ pub(crate) fn new_chain_swap(
claim_private_key: "7d3cbecfb76cb8eccc2c2131f3e744311d3655377fe8723d23acb55b041b2b16".to_string(), claim_private_key: "7d3cbecfb76cb8eccc2c2131f3e744311d3655377fe8723d23acb55b041b2b16".to_string(),
refund_private_key: "2644c60cc6cd454ea809f0e32fc2871ab7c26603e3009e1fd313ae886c137eaa".to_string(), refund_private_key: "2644c60cc6cd454ea809f0e32fc2871ab7c26603e3009e1fd313ae886c137eaa".to_string(),
payer_amount_sat: 25490, payer_amount_sat: 25490,
actual_payer_amount_sat: None,
receiver_amount_sat: 20000, receiver_amount_sat: 20000,
accepted_receiver_amount_sat: None,
claim_fees_sat: 2109, claim_fees_sat: 2109,
server_lockup_tx_id: None, server_lockup_tx_id: None,
user_lockup_tx_id, user_lockup_tx_id,

View File

@@ -161,6 +161,7 @@ pub(crate) fn new_chain_sync_data(accept_zero_conf: Option<bool>) -> ChainSyncDa
timeout_block_height: 0, timeout_block_height: 0,
payer_amount_sat: 0, payer_amount_sat: 0,
receiver_amount_sat: 0, receiver_amount_sat: 0,
accepted_receiver_amount_sat: None,
accept_zero_conf: accept_zero_conf.unwrap_or(true), accept_zero_conf: accept_zero_conf.unwrap_or(true),
created_at: 0, created_at: 0,
description: None, description: None,

View File

@@ -1644,6 +1644,27 @@ class FlutterBreezLiquidBindings {
_uniffi_breez_sdk_liquid_bindings_fn_free_bindingliquidsdkPtr _uniffi_breez_sdk_liquid_bindings_fn_free_bindingliquidsdkPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<RustCallStatus>)>(); .asFunction<void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<RustCallStatus>)>();
void uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_fees(
ffi.Pointer<ffi.Void> ptr,
RustBuffer req,
ffi.Pointer<RustCallStatus> out_status,
) {
return _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_fees(
ptr,
req,
out_status,
);
}
late final _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_feesPtr =
_lookup<
ffi.NativeFunction<
ffi.Void Function(ffi.Pointer<ffi.Void>, RustBuffer, ffi.Pointer<RustCallStatus>)>>(
'uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_fees');
late final _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_fees =
_uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_accept_payment_proposed_feesPtr
.asFunction<void Function(ffi.Pointer<ffi.Void>, RustBuffer, ffi.Pointer<RustCallStatus>)>();
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_add_event_listener( RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_add_event_listener(
ffi.Pointer<ffi.Void> ptr, ffi.Pointer<ffi.Void> ptr,
int listener, int listener,
@@ -1792,6 +1813,27 @@ class FlutterBreezLiquidBindings {
_uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_onchain_limitsPtr _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_onchain_limitsPtr
.asFunction<RustBuffer Function(ffi.Pointer<ffi.Void>, ffi.Pointer<RustCallStatus>)>(); .asFunction<RustBuffer Function(ffi.Pointer<ffi.Void>, ffi.Pointer<RustCallStatus>)>();
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_fees(
ffi.Pointer<ffi.Void> ptr,
RustBuffer req,
ffi.Pointer<RustCallStatus> out_status,
) {
return _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_fees(
ptr,
req,
out_status,
);
}
late final _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_feesPtr =
_lookup<
ffi.NativeFunction<
RustBuffer Function(ffi.Pointer<ffi.Void>, RustBuffer, ffi.Pointer<RustCallStatus>)>>(
'uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_fees');
late final _uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_fees =
_uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_fetch_payment_proposed_feesPtr
.asFunction<RustBuffer Function(ffi.Pointer<ffi.Void>, RustBuffer, ffi.Pointer<RustCallStatus>)>();
RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_get_info( RustBuffer uniffi_breez_sdk_liquid_bindings_fn_method_bindingliquidsdk_get_info(
ffi.Pointer<ffi.Void> ptr, ffi.Pointer<ffi.Void> ptr,
ffi.Pointer<RustCallStatus> out_status, ffi.Pointer<RustCallStatus> out_status,
@@ -3421,6 +3463,17 @@ class FlutterBreezLiquidBindings {
late final _uniffi_breez_sdk_liquid_bindings_checksum_func_set_logger = late final _uniffi_breez_sdk_liquid_bindings_checksum_func_set_logger =
_uniffi_breez_sdk_liquid_bindings_checksum_func_set_loggerPtr.asFunction<int Function()>(); _uniffi_breez_sdk_liquid_bindings_checksum_func_set_loggerPtr.asFunction<int Function()>();
int uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_fees() {
return _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_fees();
}
late final _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_feesPtr =
_lookup<ffi.NativeFunction<ffi.Uint16 Function()>>(
'uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_fees');
late final _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_fees =
_uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_accept_payment_proposed_feesPtr
.asFunction<int Function()>();
int uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_add_event_listener() { int uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_add_event_listener() {
return _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_add_event_listener(); return _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_add_event_listener();
} }
@@ -3509,6 +3562,17 @@ class FlutterBreezLiquidBindings {
_uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_onchain_limitsPtr _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_onchain_limitsPtr
.asFunction<int Function()>(); .asFunction<int Function()>();
int uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_fees() {
return _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_fees();
}
late final _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_feesPtr =
_lookup<ffi.NativeFunction<ffi.Uint16 Function()>>(
'uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_fees');
late final _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_fees =
_uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_fetch_payment_proposed_feesPtr
.asFunction<int Function()>();
int uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_get_info() { int uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_get_info() {
return _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_get_info(); return _uniffi_breez_sdk_liquid_bindings_checksum_method_bindingliquidsdk_get_info();
} }