Skip to content

Commit

Permalink
Expose amountless swap fees auto acceptance (#690)
Browse files Browse the repository at this point in the history
* Expose amountless swap fees auto acceptance

* Move field behind optional ones

* Add serde default to auto_accepted_fees
  • Loading branch information
danielgranhao authored Jan 24, 2025
1 parent 53fb22a commit 7841939
Show file tree
Hide file tree
Showing 22 changed files with 134 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ typedef struct wire_cst_PaymentDetails_Liquid {
typedef struct wire_cst_PaymentDetails_Bitcoin {
struct wire_cst_list_prim_u_8_strict *swap_id;
struct wire_cst_list_prim_u_8_strict *description;
bool auto_accepted_fees;
uint32_t *liquid_expiration_blockheight;
uint32_t *bitcoin_expiration_blockheight;
struct wire_cst_list_prim_u_8_strict *refund_tx_id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class SwapUpdatedTask : TaskProtocol {
func getSwapId(details: PaymentDetails?) -> String? {
if let details = details {
switch details {
case let .bitcoin(swapId, _, _, _, _, _):
case let .bitcoin(swapId, _, _, _, _, _, _):
return swapId
case let .lightning(swapId, _, _, _, _, _, _, _, _, _, _):
return swapId
Expand Down
2 changes: 1 addition & 1 deletion lib/bindings/src/breez_sdk_liquid.udl
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ dictionary LnUrlInfo {
interface PaymentDetails {
Lightning(string swap_id, string description, u32 liquid_expiration_blockheight, string? preimage, string? invoice, string? bolt12_offer, string? payment_hash, string? destination_pubkey, LnUrlInfo? lnurl_info, string? refund_tx_id, u64? refund_tx_amount_sat);
Liquid(string destination, string description);
Bitcoin(string swap_id, string description, u32? bitcoin_expiration_blockheight, u32? liquid_expiration_blockheight, string? refund_tx_id, u64? refund_tx_amount_sat);
Bitcoin(string swap_id, string description, boolean auto_accepted_fees, u32? bitcoin_expiration_blockheight, u32? liquid_expiration_blockheight, string? refund_tx_id, u64? refund_tx_amount_sat);
};

dictionary Payment {
Expand Down
3 changes: 2 additions & 1 deletion lib/core/src/chain_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,8 @@ impl ChainSwapHandler {
.inspect_err(|e| {
error!("Failed to accept zero-amount swap {id} quote: {e} - trying to erase the accepted receiver amount...");
let _ = self.persister.update_accepted_receiver_amount(&id, None);
})
})?;
self.persister.set_chain_swap_auto_accepted_fees(&id)
}
ValidateAmountlessSwapResult::RequiresUserAction {
user_lockup_amount_sat,
Expand Down
8 changes: 8 additions & 0 deletions lib/core/src/frb_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3803,13 +3803,15 @@ impl SseDecode for crate::model::PaymentDetails {
2 => {
let mut var_swapId = <String>::sse_decode(deserializer);
let mut var_description = <String>::sse_decode(deserializer);
let mut var_autoAcceptedFees = <bool>::sse_decode(deserializer);
let mut var_liquidExpirationBlockheight = <Option<u32>>::sse_decode(deserializer);
let mut var_bitcoinExpirationBlockheight = <Option<u32>>::sse_decode(deserializer);
let mut var_refundTxId = <Option<String>>::sse_decode(deserializer);
let mut var_refundTxAmountSat = <Option<u64>>::sse_decode(deserializer);
return crate::model::PaymentDetails::Bitcoin {
swap_id: var_swapId,
description: var_description,
auto_accepted_fees: var_autoAcceptedFees,
liquid_expiration_blockheight: var_liquidExpirationBlockheight,
bitcoin_expiration_blockheight: var_bitcoinExpirationBlockheight,
refund_tx_id: var_refundTxId,
Expand Down Expand Up @@ -5991,6 +5993,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PaymentDetails {
crate::model::PaymentDetails::Bitcoin {
swap_id,
description,
auto_accepted_fees,
liquid_expiration_blockheight,
bitcoin_expiration_blockheight,
refund_tx_id,
Expand All @@ -5999,6 +6002,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PaymentDetails {
2.into_dart(),
swap_id.into_into_dart().into_dart(),
description.into_into_dart().into_dart(),
auto_accepted_fees.into_into_dart().into_dart(),
liquid_expiration_blockheight.into_into_dart().into_dart(),
bitcoin_expiration_blockheight.into_into_dart().into_dart(),
refund_tx_id.into_into_dart().into_dart(),
Expand Down Expand Up @@ -8112,6 +8116,7 @@ impl SseEncode for crate::model::PaymentDetails {
crate::model::PaymentDetails::Bitcoin {
swap_id,
description,
auto_accepted_fees,
liquid_expiration_blockheight,
bitcoin_expiration_blockheight,
refund_tx_id,
Expand All @@ -8120,6 +8125,7 @@ impl SseEncode for crate::model::PaymentDetails {
<i32>::sse_encode(2, serializer);
<String>::sse_encode(swap_id, serializer);
<String>::sse_encode(description, serializer);
<bool>::sse_encode(auto_accepted_fees, serializer);
<Option<u32>>::sse_encode(liquid_expiration_blockheight, serializer);
<Option<u32>>::sse_encode(bitcoin_expiration_blockheight, serializer);
<Option<String>>::sse_encode(refund_tx_id, serializer);
Expand Down Expand Up @@ -10209,6 +10215,7 @@ mod io {
crate::model::PaymentDetails::Bitcoin {
swap_id: ans.swap_id.cst_decode(),
description: ans.description.cst_decode(),
auto_accepted_fees: ans.auto_accepted_fees.cst_decode(),
liquid_expiration_blockheight: ans
.liquid_expiration_blockheight
.cst_decode(),
Expand Down Expand Up @@ -13810,6 +13817,7 @@ mod io {
pub struct wire_cst_PaymentDetails_Bitcoin {
swap_id: *mut wire_cst_list_prim_u_8_strict,
description: *mut wire_cst_list_prim_u_8_strict,
auto_accepted_fees: bool,
liquid_expiration_blockheight: *mut u32,
bitcoin_expiration_blockheight: *mut u32,
refund_tx_id: *mut wire_cst_list_prim_u_8_strict,
Expand Down
6 changes: 6 additions & 0 deletions lib/core/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ pub(crate) struct ChainSwap {
pub(crate) state: PaymentState,
pub(crate) claim_private_key: String,
pub(crate) refund_private_key: String,
pub(crate) auto_accepted_fees: bool,
/// Version used for optimistic concurrency control within local db
#[derivative(PartialEq = "ignore")]
pub(crate) version: u64,
Expand Down Expand Up @@ -1437,6 +1438,11 @@ pub enum PaymentDetails {
/// Represents the invoice description
description: String,

/// For an amountless receive swap, this indicates if fees were automatically accepted.
/// Fees are auto accepted when the swapper proposes fees that are within the initial
/// estimate, plus the `onchain_fee_rate_leeway_sat_per_vbyte` set in the [Config], if any.
auto_accepted_fees: bool,

/// The height of the Liquid block at which the swap will no longer be valid
/// It should always be populated in case of an outgoing chain swap
liquid_expiration_blockheight: Option<u32>,
Expand Down
34 changes: 33 additions & 1 deletion lib/core/src/persist/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ impl Persister {
pair_fees_json,
actual_payer_amount_sat,
accepted_receiver_amount_sat,
auto_accepted_fees,
version,
-- Used for filtering
Expand Down Expand Up @@ -216,7 +217,8 @@ impl Persister {
pair_fees_json: row.get(20)?,
actual_payer_amount_sat: row.get(21)?,
accepted_receiver_amount_sat: row.get(22)?,
version: row.get(23)?,
auto_accepted_fees: row.get(23)?,
version: row.get(24)?,
})
}

Expand Down Expand Up @@ -372,6 +374,36 @@ impl Persister {
Ok(())
}

pub(crate) fn set_chain_swap_auto_accepted_fees(
&self,
swap_id: &str,
) -> Result<(), PaymentError> {
log::info!("Setting chain swap {swap_id}: auto_accepted_fees to TRUE");

let mut con = self.get_connection()?;
let tx = con.transaction_with_behavior(TransactionBehavior::Immediate)?;

tx.execute(
"UPDATE chain_swaps
SET auto_accepted_fees = 1
WHERE id = :id",
named_params! {
":id": swap_id,
},
)?;
self.commit_outgoing(
&tx,
swap_id,
RecordType::Chain,
Some(vec!["auto_accepted_fees".to_string()]),
)?;
tx.commit()?;
self.trigger_sync().map_err(|err| PaymentError::Generic {
err: format!("Could not trigger manual sync: {err:?}"),
})?;
Ok(())
}

// Only set the Chain Swap claim_tx_id if not set, otherwise return an error
pub(crate) fn set_chain_swap_claim_tx_id(
&self,
Expand Down
1 change: 1 addition & 0 deletions lib/core/src/persist/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,5 +248,6 @@ pub(crate) fn current_migrations() -> Vec<&'static str> {
ALTER TABLE receive_swaps ADD COLUMN destination_pubkey TEXT;
ALTER TABLE send_swaps ADD COLUMN destination_pubkey TEXT;
",
"ALTER TABLE chain_swaps ADD COLUMN auto_accepted_fees INTEGER NOT NULL DEFAULT 0;",
]
}
12 changes: 8 additions & 4 deletions lib/core/src/persist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ impl Persister {
cs.pair_fees_json,
cs.actual_payer_amount_sat,
cs.accepted_receiver_amount_sat,
cs.auto_accepted_fees,
rtx.amount_sat,
pd.destination,
pd.description,
Expand Down Expand Up @@ -515,12 +516,13 @@ impl Persister {
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(45)?;
let maybe_chain_swap_accepted_receiver_amount_sat: Option<u64> = row.get(46)?;
let maybe_chain_swap_auto_accepted_fees: Option<bool> = row.get(47)?;

let maybe_swap_refund_tx_amount_sat: Option<u64> = row.get(47)?;
let maybe_swap_refund_tx_amount_sat: Option<u64> = row.get(48)?;

let maybe_payment_details_destination: Option<String> = row.get(48)?;
let maybe_payment_details_description: Option<String> = row.get(49)?;
let maybe_payment_details_lnurl_info_json: Option<String> = row.get(50)?;
let maybe_payment_details_destination: Option<String> = row.get(49)?;
let maybe_payment_details_description: Option<String> = row.get(50)?;
let maybe_payment_details_lnurl_info_json: Option<String> = row.get(51)?;
let maybe_payment_details_lnurl_info: Option<LnUrlInfo> =
maybe_payment_details_lnurl_info_json.and_then(|info| serde_json::from_str(&info).ok());

Expand Down Expand Up @@ -701,6 +703,7 @@ impl Persister {
Some(Direction::Incoming) => (Some(expiration_blockheight), None),
Some(Direction::Outgoing) | None => (None, Some(expiration_blockheight)),
};
let auto_accepted_fees = maybe_chain_swap_auto_accepted_fees.unwrap_or(false);

PaymentDetails::Bitcoin {
swap_id,
Expand All @@ -709,6 +712,7 @@ impl Persister {
description: description.unwrap_or("Bitcoin transfer".to_string()),
liquid_expiration_blockheight,
bitcoin_expiration_blockheight,
auto_accepted_fees,
}
}
_ => PaymentDetails::Liquid {
Expand Down
2 changes: 2 additions & 0 deletions lib/core/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,7 @@ impl LiquidSdk {
refund_tx_id: None,
created_at: utils::now(),
state: PaymentState::Created,
auto_accepted_fees: false,
version: 0,
};
self.persister.insert_or_update_chain_swap(&swap)?;
Expand Down Expand Up @@ -2132,6 +2133,7 @@ impl LiquidSdk {
refund_tx_id: None,
created_at: utils::now(),
state: PaymentState::Created,
auto_accepted_fees: false,
version: 0,
};
self.persister.insert_or_update_chain_swap(&swap)?;
Expand Down
10 changes: 10 additions & 0 deletions lib/core/src/sync/model/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub(crate) struct ChainSyncData {
pub(crate) accept_zero_conf: bool,
pub(crate) created_at: u32,
pub(crate) description: Option<String>,
#[serde(default)]
pub(crate) auto_accepted_fees: bool,
}

impl ChainSyncData {
Expand All @@ -36,6 +38,9 @@ impl ChainSyncData {
"accepted_receiver_amount_sat" => {
self.accepted_receiver_amount_sat = other.accepted_receiver_amount_sat
}
"auto_accepted_fees" => {
self.auto_accepted_fees = other.auto_accepted_fees;
}
_ => continue,
}
}
Expand All @@ -54,6 +59,9 @@ impl ChainSyncData {
if update.accepted_receiver_amount_sat != swap.accepted_receiver_amount_sat {
updated_fields.push("accepted_receiver_amount_sat".to_string());
}
if update.auto_accepted_fees != swap.auto_accepted_fees {
updated_fields.push("auto_accepted_fees".to_string());
}
Some(updated_fields)
}
None => None,
Expand All @@ -80,6 +88,7 @@ impl From<ChainSwap> for ChainSyncData {
accept_zero_conf: value.accept_zero_conf,
created_at: value.created_at,
description: value.description,
auto_accepted_fees: value.auto_accepted_fees,
}
}
}
Expand Down Expand Up @@ -110,6 +119,7 @@ impl From<ChainSyncData> for ChainSwap {
user_lockup_tx_id: None,
claim_tx_id: None,
refund_tx_id: None,
auto_accepted_fees: val.auto_accepted_fees,
version: 0,
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/core/src/sync/model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub(crate) mod data;

const MESSAGE_PREFIX: &[u8; 13] = b"realtimesync:";
lazy_static! {
static ref CURRENT_SCHEMA_VERSION: Version = Version::parse("0.2.0").unwrap();
static ref CURRENT_SCHEMA_VERSION: Version = Version::parse("0.3.0").unwrap();
}

#[derive(Copy, Clone)]
Expand Down
3 changes: 3 additions & 0 deletions lib/core/src/test_utils/chain_swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ pub(crate) fn new_chain_swap(
}
}"#
.to_string(),
auto_accepted_fees: false,
version: 0
};
}
Expand Down Expand Up @@ -228,6 +229,7 @@ pub(crate) fn new_chain_swap(
}
}
}"#.to_string(),
auto_accepted_fees: false,
version: 0,
},
Direction::Outgoing => ChainSwap {
Expand Down Expand Up @@ -310,6 +312,7 @@ pub(crate) fn new_chain_swap(
}
}
}"#.to_string(),
auto_accepted_fees: false,
version: 0
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/core/src/test_utils/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,6 @@ pub(crate) fn new_chain_sync_data(accept_zero_conf: Option<bool>) -> ChainSyncDa
accept_zero_conf: accept_zero_conf.unwrap_or(true),
created_at: 0,
description: None,
auto_accepted_fees: false,
}
}
13 changes: 9 additions & 4 deletions packages/dart/lib/src/frb_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2709,10 +2709,11 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return PaymentDetails_Bitcoin(
swapId: dco_decode_String(raw[1]),
description: dco_decode_String(raw[2]),
liquidExpirationBlockheight: dco_decode_opt_box_autoadd_u_32(raw[3]),
bitcoinExpirationBlockheight: dco_decode_opt_box_autoadd_u_32(raw[4]),
refundTxId: dco_decode_opt_String(raw[5]),
refundTxAmountSat: dco_decode_opt_box_autoadd_u_64(raw[6]),
autoAcceptedFees: dco_decode_bool(raw[3]),
liquidExpirationBlockheight: dco_decode_opt_box_autoadd_u_32(raw[4]),
bitcoinExpirationBlockheight: dco_decode_opt_box_autoadd_u_32(raw[5]),
refundTxId: dco_decode_opt_String(raw[6]),
refundTxAmountSat: dco_decode_opt_box_autoadd_u_64(raw[7]),
);
default:
throw Exception("unreachable");
Expand Down Expand Up @@ -4899,13 +4900,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
case 2:
var var_swapId = sse_decode_String(deserializer);
var var_description = sse_decode_String(deserializer);
var var_autoAcceptedFees = sse_decode_bool(deserializer);
var var_liquidExpirationBlockheight = sse_decode_opt_box_autoadd_u_32(deserializer);
var var_bitcoinExpirationBlockheight = sse_decode_opt_box_autoadd_u_32(deserializer);
var var_refundTxId = sse_decode_opt_String(deserializer);
var var_refundTxAmountSat = sse_decode_opt_box_autoadd_u_64(deserializer);
return PaymentDetails_Bitcoin(
swapId: var_swapId,
description: var_description,
autoAcceptedFees: var_autoAcceptedFees,
liquidExpirationBlockheight: var_liquidExpirationBlockheight,
bitcoinExpirationBlockheight: var_bitcoinExpirationBlockheight,
refundTxId: var_refundTxId,
Expand Down Expand Up @@ -6915,6 +6918,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
case PaymentDetails_Bitcoin(
swapId: final swapId,
description: final description,
autoAcceptedFees: final autoAcceptedFees,
liquidExpirationBlockheight: final liquidExpirationBlockheight,
bitcoinExpirationBlockheight: final bitcoinExpirationBlockheight,
refundTxId: final refundTxId,
Expand All @@ -6923,6 +6927,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_i_32(2, serializer);
sse_encode_String(swapId, serializer);
sse_encode_String(description, serializer);
sse_encode_bool(autoAcceptedFees, serializer);
sse_encode_opt_box_autoadd_u_32(liquidExpirationBlockheight, serializer);
sse_encode_opt_box_autoadd_u_32(bitcoinExpirationBlockheight, serializer);
sse_encode_opt_String(refundTxId, serializer);
Expand Down
5 changes: 5 additions & 0 deletions packages/dart/lib/src/frb_generated.io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2978,6 +2978,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
if (apiObj is PaymentDetails_Bitcoin) {
var pre_swap_id = cst_encode_String(apiObj.swapId);
var pre_description = cst_encode_String(apiObj.description);
var pre_auto_accepted_fees = cst_encode_bool(apiObj.autoAcceptedFees);
var pre_liquid_expiration_blockheight =
cst_encode_opt_box_autoadd_u_32(apiObj.liquidExpirationBlockheight);
var pre_bitcoin_expiration_blockheight =
Expand All @@ -2987,6 +2988,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
wireObj.tag = 2;
wireObj.kind.Bitcoin.swap_id = pre_swap_id;
wireObj.kind.Bitcoin.description = pre_description;
wireObj.kind.Bitcoin.auto_accepted_fees = pre_auto_accepted_fees;
wireObj.kind.Bitcoin.liquid_expiration_blockheight = pre_liquid_expiration_blockheight;
wireObj.kind.Bitcoin.bitcoin_expiration_blockheight = pre_bitcoin_expiration_blockheight;
wireObj.kind.Bitcoin.refund_tx_id = pre_refund_tx_id;
Expand Down Expand Up @@ -6409,6 +6411,9 @@ final class wire_cst_PaymentDetails_Bitcoin extends ffi.Struct {

external ffi.Pointer<wire_cst_list_prim_u_8_strict> description;

@ffi.Bool()
external bool auto_accepted_fees;

external ffi.Pointer<ffi.Uint32> liquid_expiration_blockheight;

external ffi.Pointer<ffi.Uint32> bitcoin_expiration_blockheight;
Expand Down
Loading

0 comments on commit 7841939

Please sign in to comment.