diff --git a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h index 0a2d51351..77751cc74 100644 --- a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h +++ b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h @@ -472,6 +472,7 @@ typedef struct wire_cst_ln_url_info { typedef struct wire_cst_PaymentDetails_Lightning { struct wire_cst_list_prim_u_8_strict *swap_id; struct wire_cst_list_prim_u_8_strict *description; + uint32_t *expiry_timestamp; struct wire_cst_list_prim_u_8_strict *preimage; struct wire_cst_list_prim_u_8_strict *bolt11; struct wire_cst_list_prim_u_8_strict *bolt12_offer; @@ -489,6 +490,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; + uint32_t *expiry_timestamp; struct wire_cst_list_prim_u_8_strict *refund_tx_id; uint64_t *refund_tx_amount_sat; } wire_cst_PaymentDetails_Bitcoin; diff --git a/lib/bindings/langs/swift/Sources/BreezSDKLiquid/Task/SwapUpdated.swift b/lib/bindings/langs/swift/Sources/BreezSDKLiquid/Task/SwapUpdated.swift index fd70f715b..bec2dce0a 100644 --- a/lib/bindings/langs/swift/Sources/BreezSDKLiquid/Task/SwapUpdated.swift +++ b/lib/bindings/langs/swift/Sources/BreezSDKLiquid/Task/SwapUpdated.swift @@ -52,9 +52,9 @@ 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, _, _, _, _, _, _, _, _): + case let .lightning(swapId, _, _, _, _, _, _, _, _, _): return swapId default: break diff --git a/lib/bindings/src/breez_sdk_liquid.udl b/lib/bindings/src/breez_sdk_liquid.udl index ba42b3a86..45590149a 100644 --- a/lib/bindings/src/breez_sdk_liquid.udl +++ b/lib/bindings/src/breez_sdk_liquid.udl @@ -553,9 +553,9 @@ dictionary LnUrlInfo { [Enum] interface PaymentDetails { - Lightning(string swap_id, string description, string? preimage, string? bolt11, string? bolt12_offer, string? payment_hash, LnUrlInfo? lnurl_info, string? refund_tx_id, u64? refund_tx_amount_sat); + Lightning(string swap_id, string description, u32? expiry_timestamp, string? preimage, string? bolt11, string? bolt12_offer, string? payment_hash, LnUrlInfo? lnurl_info, string? refund_tx_id, u64? refund_tx_amount_sat); Liquid(string destination, string description); - Bitcoin(string swap_id, string description, string? refund_tx_id, u64? refund_tx_amount_sat); + Bitcoin(string swap_id, string description, u32? expiry_timestamp, string? refund_tx_id, u64? refund_tx_amount_sat); }; dictionary Payment { diff --git a/lib/core/src/chain/bitcoin.rs b/lib/core/src/chain/bitcoin.rs index 91452b04b..7be1493bc 100644 --- a/lib/core/src/chain/bitcoin.rs +++ b/lib/core/src/chain/bitcoin.rs @@ -20,6 +20,8 @@ use crate::{ prelude::Utxo, }; +pub(crate) const ESTIMATED_BITCOIN_BLOCK_TIME_SEC: u32 = 600; + /// Trait implemented by types that can fetch data from a blockchain data source. #[allow(dead_code)] #[async_trait] diff --git a/lib/core/src/chain/liquid.rs b/lib/core/src/chain/liquid.rs index 03e1f617a..7d41a92f1 100644 --- a/lib/core/src/chain/liquid.rs +++ b/lib/core/src/chain/liquid.rs @@ -5,6 +5,7 @@ use async_trait::async_trait; use boltz_client::ToHex; use log::{info, warn}; use lwk_wollet::elements::hex::FromHex; +use lwk_wollet::elements::BlockHeader; use lwk_wollet::{ elements::{ pset::serialize::Serialize, Address, BlockHash, OutPoint, Script, Transaction, Txid, @@ -22,11 +23,12 @@ use crate::{ }; const LIQUID_ESPLORA_URL: &str = "https://lq1.breez.technology/liquid/api"; +pub(crate) const ESTIMATED_LIQUID_BLOCK_TIME_SEC: u32 = 60; #[async_trait] pub trait LiquidChainService: Send + Sync { /// Get the blockchain latest block - async fn tip(&mut self) -> Result; + async fn tip(&mut self) -> Result; /// Broadcast a transaction async fn broadcast(&self, tx: &Transaction, swap_id: Option<&str>) -> Result; @@ -99,8 +101,8 @@ impl HybridLiquidChainService { #[async_trait] impl LiquidChainService for HybridLiquidChainService { - async fn tip(&mut self) -> Result { - Ok(self.electrum_client.tip()?.height) + async fn tip(&mut self) -> Result { + Ok(self.electrum_client.tip()?) } async fn broadcast(&self, tx: &Transaction, swap_id: Option<&str>) -> Result { diff --git a/lib/core/src/frb_generated.rs b/lib/core/src/frb_generated.rs index f2d83df17..fd5e6f4e2 100644 --- a/lib/core/src/frb_generated.rs +++ b/lib/core/src/frb_generated.rs @@ -3619,6 +3619,7 @@ impl SseDecode for crate::model::PaymentDetails { 0 => { let mut var_swapId = ::sse_decode(deserializer); let mut var_description = ::sse_decode(deserializer); + let mut var_expiryTimestamp = >::sse_decode(deserializer); let mut var_preimage = >::sse_decode(deserializer); let mut var_bolt11 = >::sse_decode(deserializer); let mut var_bolt12Offer = >::sse_decode(deserializer); @@ -3629,6 +3630,7 @@ impl SseDecode for crate::model::PaymentDetails { return crate::model::PaymentDetails::Lightning { swap_id: var_swapId, description: var_description, + expiry_timestamp: var_expiryTimestamp, preimage: var_preimage, bolt11: var_bolt11, bolt12_offer: var_bolt12Offer, @@ -3649,11 +3651,13 @@ impl SseDecode for crate::model::PaymentDetails { 2 => { let mut var_swapId = ::sse_decode(deserializer); let mut var_description = ::sse_decode(deserializer); + let mut var_expiryTimestamp = >::sse_decode(deserializer); let mut var_refundTxId = >::sse_decode(deserializer); let mut var_refundTxAmountSat = >::sse_decode(deserializer); return crate::model::PaymentDetails::Bitcoin { swap_id: var_swapId, description: var_description, + expiry_timestamp: var_expiryTimestamp, refund_tx_id: var_refundTxId, refund_tx_amount_sat: var_refundTxAmountSat, }; @@ -5687,6 +5691,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PaymentDetails { crate::model::PaymentDetails::Lightning { swap_id, description, + expiry_timestamp, preimage, bolt11, bolt12_offer, @@ -5698,6 +5703,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::PaymentDetails { 0.into_dart(), swap_id.into_into_dart().into_dart(), description.into_into_dart().into_dart(), + expiry_timestamp.into_into_dart().into_dart(), preimage.into_into_dart().into_dart(), bolt11.into_into_dart().into_dart(), bolt12_offer.into_into_dart().into_dart(), @@ -5719,12 +5725,14 @@ impl flutter_rust_bridge::IntoDart for crate::model::PaymentDetails { crate::model::PaymentDetails::Bitcoin { swap_id, description, + expiry_timestamp, refund_tx_id, refund_tx_amount_sat, } => [ 2.into_dart(), swap_id.into_into_dart().into_dart(), description.into_into_dart().into_dart(), + expiry_timestamp.into_into_dart().into_dart(), refund_tx_id.into_into_dart().into_dart(), refund_tx_amount_sat.into_into_dart().into_dart(), ] @@ -7743,6 +7751,7 @@ impl SseEncode for crate::model::PaymentDetails { crate::model::PaymentDetails::Lightning { swap_id, description, + expiry_timestamp, preimage, bolt11, bolt12_offer, @@ -7754,6 +7763,7 @@ impl SseEncode for crate::model::PaymentDetails { ::sse_encode(0, serializer); ::sse_encode(swap_id, serializer); ::sse_encode(description, serializer); + >::sse_encode(expiry_timestamp, serializer); >::sse_encode(preimage, serializer); >::sse_encode(bolt11, serializer); >::sse_encode(bolt12_offer, serializer); @@ -7773,12 +7783,14 @@ impl SseEncode for crate::model::PaymentDetails { crate::model::PaymentDetails::Bitcoin { swap_id, description, + expiry_timestamp, refund_tx_id, refund_tx_amount_sat, } => { ::sse_encode(2, serializer); ::sse_encode(swap_id, serializer); ::sse_encode(description, serializer); + >::sse_encode(expiry_timestamp, serializer); >::sse_encode(refund_tx_id, serializer); >::sse_encode(refund_tx_amount_sat, serializer); } @@ -9758,6 +9770,7 @@ mod io { crate::model::PaymentDetails::Lightning { swap_id: ans.swap_id.cst_decode(), description: ans.description.cst_decode(), + expiry_timestamp: ans.expiry_timestamp.cst_decode(), preimage: ans.preimage.cst_decode(), bolt11: ans.bolt11.cst_decode(), bolt12_offer: ans.bolt12_offer.cst_decode(), @@ -9779,6 +9792,7 @@ mod io { crate::model::PaymentDetails::Bitcoin { swap_id: ans.swap_id.cst_decode(), description: ans.description.cst_decode(), + expiry_timestamp: ans.expiry_timestamp.cst_decode(), refund_tx_id: ans.refund_tx_id.cst_decode(), refund_tx_amount_sat: ans.refund_tx_amount_sat.cst_decode(), } @@ -13201,6 +13215,7 @@ mod io { pub struct wire_cst_PaymentDetails_Lightning { swap_id: *mut wire_cst_list_prim_u_8_strict, description: *mut wire_cst_list_prim_u_8_strict, + expiry_timestamp: *mut u32, preimage: *mut wire_cst_list_prim_u_8_strict, bolt11: *mut wire_cst_list_prim_u_8_strict, bolt12_offer: *mut wire_cst_list_prim_u_8_strict, @@ -13220,6 +13235,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, + expiry_timestamp: *mut u32, refund_tx_id: *mut wire_cst_list_prim_u_8_strict, refund_tx_amount_sat: *mut u64, } diff --git a/lib/core/src/model.rs b/lib/core/src/model.rs index e24508f6b..88dc737f5 100644 --- a/lib/core/src/model.rs +++ b/lib/core/src/model.rs @@ -735,6 +735,7 @@ pub(crate) struct ChainSwap { /// Persisted as soon as a refund tx is broadcast pub(crate) refund_tx_id: Option, pub(crate) created_at: u32, + pub(crate) expiry_at: Option, pub(crate) state: PaymentState, pub(crate) claim_private_key: String, pub(crate) refund_private_key: String, @@ -879,6 +880,7 @@ pub(crate) struct SendSwap { /// Persisted as soon as a refund tx is broadcast pub(crate) refund_tx_id: Option, pub(crate) created_at: u32, + pub(crate) expiry_at: Option, pub(crate) state: PaymentState, pub(crate) refund_private_key: String, } @@ -972,6 +974,7 @@ pub(crate) struct ReceiveSwap { /// Until the lockup tx is seen in the mempool, it contains the swap creation time. /// Afterwards, it shows the lockup tx creation time. pub(crate) created_at: u32, + pub(crate) expiry_at: Option, pub(crate) state: PaymentState, } impl ReceiveSwap { @@ -1122,6 +1125,13 @@ pub enum PaymentState { /// When the refund tx is broadcast, `refund_tx_id` is set in the swap. RefundPending = 6, } + +impl PaymentState { + pub(crate) fn is_ongoing(&self) -> bool { + matches!(self, Self::Created | Self::Pending) + } +} + impl ToSql for PaymentState { fn to_sql(&self) -> rusqlite::Result> { Ok(rusqlite::types::ToSqlOutput::from(*self as i8)) @@ -1238,6 +1248,9 @@ pub struct PaymentSwapData { /// Swap creation timestamp pub created_at: u32, + /// Swap expiry timestamp + pub expiry_at: Option, + pub preimage: Option, pub bolt11: Option, pub bolt12_offer: Option, @@ -1288,7 +1301,10 @@ pub enum PaymentDetails { /// Represents the invoice description description: String, - /// In case of a Send swap, this is the preimage of the paid invoice (proof of payment). + /// The estimated swap expiry + expiry_timestamp: Option, + + /// The preimage of the paid invoice (proof of payment). preimage: Option, /// Represents the Bolt11 invoice associated with a payment @@ -1325,6 +1341,9 @@ pub enum PaymentDetails { /// Represents the invoice description description: String, + /// The estimated swap expiry + expiry_timestamp: Option, + /// For a Send swap which was refunded, this is the refund tx id refund_tx_id: Option, @@ -1434,7 +1453,18 @@ impl Payment { swapper_fees_sat: Some(swap.swapper_fees_sat), payment_type, status: swap.status, - details: payment_details, + details: PaymentDetails::Lightning { + swap_id: swap.swap_id, + preimage: swap.preimage, + bolt11: swap.bolt11, + bolt12_offer: swap.bolt12_offer, + payment_hash: swap.payment_hash, + description: swap.description, + expiry_timestamp: swap.expiry_at, + lnurl_info: None, + refund_tx_id: swap.refund_tx_id, + refund_tx_amount_sat: swap.refund_tx_amount_sat, + }, } } diff --git a/lib/core/src/persist/chain.rs b/lib/core/src/persist/chain.rs index cec6ca00a..d58ddae9f 100644 --- a/lib/core/src/persist/chain.rs +++ b/lib/core/src/persist/chain.rs @@ -35,9 +35,10 @@ impl Persister { refund_private_key, claim_fees_sat, created_at, + expiry_at, state ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING", ( &chain_swap.id, @@ -54,6 +55,7 @@ impl Persister { &chain_swap.refund_private_key, &chain_swap.claim_fees_sat, &chain_swap.created_at, + &chain_swap.expiry_at, &chain_swap.state, ), )?; @@ -71,6 +73,7 @@ impl Persister { claim_tx_id = :claim_tx_id, refund_tx_id = :refund_tx_id, pair_fees_json = :pair_fees_json, + expiry_at = :expiry_at, state = :state WHERE id = :id", @@ -86,6 +89,7 @@ impl Persister { ":claim_tx_id": &chain_swap.claim_tx_id, ":refund_tx_id": &chain_swap.refund_tx_id, ":pair_fees_json": &chain_swap.pair_fees_json, + ":expiry_at": &chain_swap.expiry_at, ":state": &chain_swap.state, }, )?; @@ -134,6 +138,7 @@ impl Persister { claim_tx_id, refund_tx_id, created_at, + expiry_at, state, pair_fees_json FROM chain_swaps @@ -183,8 +188,9 @@ impl Persister { claim_tx_id: row.get(16)?, refund_tx_id: row.get(17)?, created_at: row.get(18)?, - state: row.get(19)?, - pair_fees_json: row.get(20)?, + expiry_at: row.get(19)?, + state: row.get(20)?, + pair_fees_json: row.get(21)?, }) } diff --git a/lib/core/src/persist/migrations.rs b/lib/core/src/persist/migrations.rs index 0b9bb500d..b71b789bd 100644 --- a/lib/core/src/persist/migrations.rs +++ b/lib/core/src/persist/migrations.rs @@ -214,5 +214,10 @@ pub(crate) fn current_migrations() -> Vec<&'static str> { ) STRICT;", "ALTER TABLE receive_swaps DROP COLUMN mrh_script_pubkey;", "ALTER TABLE payment_details ADD COLUMN lnurl_info_json TEXT;", + " + ALTER TABLE receive_swaps ADD COLUMN expiry_at INTEGER; + ALTER TABLE send_swaps ADD COLUMN expiry_at INTEGER; + ALTER TABLE chain_swaps ADD COLUMN expiry_at INTEGER; + ", ] } diff --git a/lib/core/src/persist/mod.rs b/lib/core/src/persist/mod.rs index 30e88df42..3d4ce757c 100644 --- a/lib/core/src/persist/mod.rs +++ b/lib/core/src/persist/mod.rs @@ -346,6 +346,7 @@ impl Persister { ptx.is_confirmed, rs.id, rs.created_at, + rs.expiry_at, rs.invoice, rs.payment_hash, rs.description, @@ -356,6 +357,7 @@ impl Persister { rs.pair_fees_json, ss.id, ss.created_at, + ss.expiry_at, ss.invoice, ss.bolt12_offer, ss.payment_hash, @@ -368,6 +370,7 @@ impl Persister { ss.pair_fees_json, cs.id, cs.created_at, + cs.expiry_at, cs.direction, cs.preimage, cs.description, @@ -434,51 +437,54 @@ impl Persister { let maybe_receive_swap_id: Option = row.get(6)?; let maybe_receive_swap_created_at: Option = row.get(7)?; - let maybe_receive_swap_invoice: Option = row.get(8)?; - let maybe_receive_swap_payment_hash: Option = row.get(9)?; - let maybe_receive_swap_description: Option = row.get(10)?; - let maybe_receive_swap_preimage: Option = row.get(11)?; - let maybe_receive_swap_payer_amount_sat: Option = row.get(12)?; - let maybe_receive_swap_receiver_amount_sat: Option = row.get(13)?; - let maybe_receive_swap_receiver_state: Option = row.get(14)?; - let maybe_receive_swap_pair_fees_json: Option = row.get(15)?; + let maybe_receive_swap_expiry_at: Option = row.get(8)?; + let maybe_receive_swap_invoice: Option = row.get(9)?; + let maybe_receive_swap_payment_hash: Option = row.get(10)?; + let maybe_receive_swap_description: Option = row.get(11)?; + let maybe_receive_swap_preimage: Option = row.get(12)?; + let maybe_receive_swap_payer_amount_sat: Option = row.get(13)?; + let maybe_receive_swap_receiver_amount_sat: Option = row.get(14)?; + let maybe_receive_swap_receiver_state: Option = row.get(15)?; + let maybe_receive_swap_pair_fees_json: Option = row.get(16)?; let maybe_receive_swap_pair_fees: Option = maybe_receive_swap_pair_fees_json.and_then(|pair| serde_json::from_str(&pair).ok()); - let maybe_send_swap_id: Option = row.get(16)?; - let maybe_send_swap_created_at: Option = row.get(17)?; - let maybe_send_swap_invoice: Option = row.get(18)?; - let maybe_send_swap_bolt12_offer: Option = row.get(19)?; - let maybe_send_swap_payment_hash: Option = row.get(20)?; - let maybe_send_swap_description: Option = row.get(21)?; - let maybe_send_swap_preimage: Option = row.get(22)?; - let maybe_send_swap_refund_tx_id: Option = row.get(23)?; - let maybe_send_swap_payer_amount_sat: Option = row.get(24)?; - let maybe_send_swap_receiver_amount_sat: Option = row.get(25)?; - let maybe_send_swap_state: Option = row.get(26)?; - let maybe_send_swap_pair_fees_json: Option = row.get(27)?; + let maybe_send_swap_id: Option = row.get(17)?; + let maybe_send_swap_created_at: Option = row.get(18)?; + let maybe_send_swap_expiry_at: Option = row.get(19)?; + let maybe_send_swap_invoice: Option = row.get(20)?; + let maybe_send_swap_bolt12_offer: Option = row.get(21)?; + let maybe_send_swap_payment_hash: Option = row.get(22)?; + let maybe_send_swap_description: Option = row.get(23)?; + let maybe_send_swap_preimage: Option = row.get(24)?; + let maybe_send_swap_refund_tx_id: Option = row.get(25)?; + let maybe_send_swap_payer_amount_sat: Option = row.get(26)?; + let maybe_send_swap_receiver_amount_sat: Option = row.get(27)?; + let maybe_send_swap_state: Option = row.get(28)?; + let maybe_send_swap_pair_fees_json: Option = row.get(29)?; let maybe_send_swap_pair_fees: Option = maybe_send_swap_pair_fees_json.and_then(|pair| serde_json::from_str(&pair).ok()); - let maybe_chain_swap_id: Option = row.get(28)?; - let maybe_chain_swap_created_at: Option = row.get(29)?; - let maybe_chain_swap_direction: Option = row.get(30)?; - let maybe_chain_swap_preimage: Option = row.get(31)?; - let maybe_chain_swap_description: Option = row.get(32)?; - let maybe_chain_swap_refund_tx_id: Option = row.get(33)?; - let maybe_chain_swap_payer_amount_sat: Option = row.get(34)?; - let maybe_chain_swap_receiver_amount_sat: Option = row.get(35)?; - let maybe_chain_swap_claim_address: Option = row.get(36)?; - let maybe_chain_swap_state: Option = row.get(37)?; - let maybe_chain_swap_pair_fees_json: Option = row.get(38)?; + let maybe_chain_swap_id: Option = row.get(30)?; + let maybe_chain_swap_created_at: Option = row.get(31)?; + let maybe_chain_swap_expiry_at: Option = row.get(32)?; + let maybe_chain_swap_direction: Option = row.get(33)?; + let maybe_chain_swap_preimage: Option = row.get(34)?; + let maybe_chain_swap_description: Option = row.get(35)?; + let maybe_chain_swap_refund_tx_id: Option = row.get(36)?; + let maybe_chain_swap_payer_amount_sat: Option = row.get(37)?; + let maybe_chain_swap_receiver_amount_sat: Option = row.get(38)?; + let maybe_chain_swap_claim_address: Option = row.get(39)?; + let maybe_chain_swap_state: Option = row.get(40)?; + let maybe_chain_swap_pair_fees_json: Option = row.get(41)?; let maybe_chain_swap_pair_fees: Option = maybe_chain_swap_pair_fees_json.and_then(|pair| serde_json::from_str(&pair).ok()); - let maybe_swap_refund_tx_amount_sat: Option = row.get(39)?; + let maybe_swap_refund_tx_amount_sat: Option = row.get(42)?; - let maybe_payment_details_destination: Option = row.get(40)?; - let maybe_payment_details_description: Option = row.get(41)?; - let maybe_payment_details_lnurl_info_json: Option = row.get(42)?; + let maybe_payment_details_destination: Option = row.get(43)?; + let maybe_payment_details_description: Option = row.get(44)?; + let maybe_payment_details_lnurl_info_json: Option = row.get(45)?; let maybe_payment_details_lnurl_info: Option = maybe_payment_details_lnurl_info_json.and_then(|info| serde_json::from_str(&info).ok()); @@ -491,6 +497,7 @@ impl Persister { swap_id: receive_swap_id, swap_type: PaymentSwapType::Receive, created_at: maybe_receive_swap_created_at.unwrap_or(utils::now()), + expiry_at: maybe_receive_swap_expiry_at, preimage: maybe_receive_swap_preimage, bolt11: maybe_receive_swap_invoice.clone(), bolt12_offer: None, // Bolt12 not supported for Receive Swaps @@ -521,6 +528,7 @@ impl Persister { swap_id: send_swap_id, swap_type: PaymentSwapType::Send, created_at: maybe_send_swap_created_at.unwrap_or(utils::now()), + expiry_at: maybe_send_swap_expiry_at, preimage: maybe_send_swap_preimage, bolt11: match maybe_send_swap_bolt12_offer.is_some() { true => None, // We don't expose the Bolt12 invoice @@ -556,6 +564,7 @@ impl Persister { swap_id: chain_swap_id, swap_type: PaymentSwapType::Chain, created_at: maybe_chain_swap_created_at.unwrap_or(utils::now()), + expiry_at: maybe_chain_swap_expiry_at, preimage: maybe_chain_swap_preimage, bolt11: None, bolt12_offer: None, // Bolt12 not supported for Chain Swaps @@ -587,6 +596,7 @@ impl Persister { PaymentSwapData { swap_type: PaymentSwapType::Receive, swap_id, + expiry_at, bolt11, bolt12_offer, payment_hash, @@ -598,6 +608,7 @@ impl Persister { | PaymentSwapData { swap_type: PaymentSwapType::Send, swap_id, + expiry_at, bolt11, bolt12_offer, payment_hash, @@ -616,10 +627,12 @@ impl Persister { refund_tx_id, refund_tx_amount_sat, description: description.unwrap_or("Lightning transfer".to_string()), + expiry_timestamp: expiry_at, }, Some(PaymentSwapData { swap_type: PaymentSwapType::Chain, swap_id, + expiry_at, refund_tx_id, refund_tx_amount_sat, .. @@ -628,6 +641,7 @@ impl Persister { refund_tx_id, refund_tx_amount_sat, description: description.unwrap_or("Bitcoin transfer".to_string()), + expiry_timestamp: expiry_at, }, _ => PaymentDetails::Liquid { destination: maybe_payment_details_destination diff --git a/lib/core/src/persist/receive.rs b/lib/core/src/persist/receive.rs index 2f6d81367..e1f57580f 100644 --- a/lib/core/src/persist/receive.rs +++ b/lib/core/src/persist/receive.rs @@ -29,12 +29,13 @@ impl Persister { payer_amount_sat, receiver_amount_sat, created_at, + expiry_at, claim_fees_sat, mrh_address, state, pair_fees_json ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING ", ( @@ -48,6 +49,7 @@ impl Persister { &receive_swap.payer_amount_sat, &receive_swap.receiver_amount_sat, &receive_swap.created_at, + &receive_swap.expiry_at, &receive_swap.claim_fees_sat, &receive_swap.mrh_address, &receive_swap.state, @@ -62,6 +64,7 @@ impl Persister { claim_tx_id = :claim_tx_id, lockup_tx_id = :lockup_tx_id, mrh_tx_id = :mrh_tx_id, + expiry_at = :expiry_at, state = :state WHERE id = :id", @@ -71,6 +74,7 @@ impl Persister { ":claim_tx_id": &receive_swap.claim_tx_id, ":lockup_tx_id": &receive_swap.lockup_tx_id, ":mrh_tx_id": &receive_swap.mrh_tx_id, + ":expiry_at": &receive_swap.expiry_at, ":state": &receive_swap.state, }, )?; @@ -119,6 +123,7 @@ impl Persister { rs.mrh_address, rs.mrh_tx_id, rs.created_at, + rs.expiry_at, rs.state, rs.pair_fees_json FROM receive_swaps AS rs @@ -164,8 +169,9 @@ impl Persister { mrh_address: row.get(12)?, mrh_tx_id: row.get(13)?, created_at: row.get(14)?, - state: row.get(15)?, - pair_fees_json: row.get(16)?, + expiry_at: row.get(15)?, + state: row.get(16)?, + pair_fees_json: row.get(17)?, }) } diff --git a/lib/core/src/persist/send.rs b/lib/core/src/persist/send.rs index 0f36766c1..c63b3ae62 100644 --- a/lib/core/src/persist/send.rs +++ b/lib/core/src/persist/send.rs @@ -29,10 +29,11 @@ impl Persister { create_response_json, refund_private_key, created_at, + expiry_at, state, pair_fees_json ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING ", ( @@ -46,6 +47,7 @@ impl Persister { &send_swap.create_response_json, &send_swap.refund_private_key, &send_swap.created_at, + &send_swap.expiry_at, &send_swap.state, &send_swap.pair_fees_json, ), @@ -58,6 +60,7 @@ impl Persister { preimage = :preimage, lockup_tx_id = :lockup_tx_id, refund_tx_id = :refund_tx_id, + expiry_at = :expiry_at, state = :state WHERE id = :id", @@ -67,6 +70,7 @@ impl Persister { ":preimage": &send_swap.preimage, ":lockup_tx_id": &send_swap.lockup_tx_id, ":refund_tx_id": &send_swap.refund_tx_id, + ":expiry_at": &send_swap.expiry_at, ":state": &send_swap.state, }, )?; @@ -131,6 +135,7 @@ impl Persister { lockup_tx_id, refund_tx_id, created_at, + expiry_at, state, pair_fees_json FROM send_swaps @@ -171,8 +176,9 @@ impl Persister { lockup_tx_id: row.get(10)?, refund_tx_id: row.get(11)?, created_at: row.get(12)?, - state: row.get(13)?, - pair_fees_json: row.get(14)?, + expiry_at: row.get(13)?, + state: row.get(14)?, + pair_fees_json: row.get(15)?, }) } diff --git a/lib/core/src/recover/recoverer.rs b/lib/core/src/recover/recoverer.rs index 9efc3c681..406f4499d 100644 --- a/lib/core/src/recover/recoverer.rs +++ b/lib/core/src/recover/recoverer.rs @@ -12,6 +12,8 @@ use lwk_wollet::hashes::{sha256, Hash as _}; use lwk_wollet::WalletTx; use tokio::sync::Mutex; +use crate::chain::bitcoin::ESTIMATED_BITCOIN_BLOCK_TIME_SEC; +use crate::chain::liquid::ESTIMATED_LIQUID_BLOCK_TIME_SEC; use crate::prelude::{Direction, Swap}; use crate::wallet::OnchainWallet; use crate::{ @@ -150,8 +152,8 @@ impl Recoverer { &swaps_list.receive_chain_swap_immutable_data_by_swap_id, )?; - let bitcoin_height = self.bitcoin_chain_service.lock().await.tip()?.height as u32; - let liquid_height = self.liquid_chain_service.lock().await.tip().await?; + let bitcoin_tip = self.bitcoin_chain_service.lock().await.tip()?; + let liquid_tip = self.liquid_chain_service.lock().await.tip().await?; for swap in swaps.iter_mut() { let swap_id = &swap.id(); @@ -161,11 +163,20 @@ impl Recoverer { log::warn!("Could not apply recovered data for Send swap {swap_id}: recovery data not found"); continue; }; - let is_expired = liquid_height - >= send_swap.get_boltz_create_response()?.timeout_block_height as u32; + let timeout_block_height = + send_swap.get_boltz_create_response()?.timeout_block_height as u32; + let is_expired = liquid_tip.height >= timeout_block_height; if let Some(new_state) = recovered_data.derive_partial_state(is_expired) { send_swap.state = new_state; } + // Stop updating the expiry when the swap is expired or complete + if !is_expired && send_swap.state.is_ongoing() { + send_swap.expiry_at = Some( + liquid_tip.time + + (timeout_block_height.saturating_sub(liquid_tip.height) + * ESTIMATED_LIQUID_BLOCK_TIME_SEC), + ); + } send_swap.lockup_tx_id = recovered_data .lockup_tx_id .clone() @@ -183,13 +194,21 @@ impl Recoverer { log::warn!("Could not apply recovered data for Receive swap {swap_id}: recovery data not found"); continue; }; - let is_expired = liquid_height - >= receive_swap - .get_boltz_create_response()? - .timeout_block_height; + let timeout_block_height = receive_swap + .get_boltz_create_response()? + .timeout_block_height; + let is_expired = liquid_tip.height >= timeout_block_height; if let Some(new_state) = recovered_data.derive_partial_state(is_expired) { receive_swap.state = new_state; } + // Stop updating the expiry when the swap is expired or complete + if !is_expired && receive_swap.state.is_ongoing() { + receive_swap.expiry_at = Some( + liquid_tip.time + + (timeout_block_height.saturating_sub(liquid_tip.height) + * ESTIMATED_LIQUID_BLOCK_TIME_SEC), + ); + } receive_swap.claim_tx_id = recovered_data .claim_tx_id .clone() @@ -213,13 +232,24 @@ impl Recoverer { log::warn!("Could not apply recovered data for incoming Chain swap {swap_id}: recovery data not found"); continue; }; - let is_expired = bitcoin_height >= chain_swap.timeout_block_height; + let is_expired = + bitcoin_tip.height as u32 >= chain_swap.timeout_block_height; let min_lockup_amount_sat = chain_swap.payer_amount_sat; if let Some(new_state) = recovered_data.derive_partial_state(min_lockup_amount_sat, is_expired) { chain_swap.state = new_state; } + // Stop updating the expiry when the swap is expired or complete + if !is_expired && chain_swap.state.is_ongoing() { + chain_swap.expiry_at = Some( + bitcoin_tip.header.time + + (chain_swap + .timeout_block_height + .saturating_sub(bitcoin_tip.height as u32) + * ESTIMATED_BITCOIN_BLOCK_TIME_SEC), + ); + } chain_swap.server_lockup_tx_id = recovered_data .lbtc_server_lockup_tx_id .clone() @@ -245,10 +275,20 @@ impl Recoverer { log::warn!("Could not apply recovered data for outgoing Chain swap {swap_id}: recovery data not found"); continue; }; - let is_expired = liquid_height >= chain_swap.timeout_block_height; + let is_expired = liquid_tip.height >= chain_swap.timeout_block_height; if let Some(new_state) = recovered_data.derive_partial_state(is_expired) { chain_swap.state = new_state; } + // Stop updating the expiry when the swap is expired or complete + if !is_expired && chain_swap.state.is_ongoing() { + chain_swap.expiry_at = Some( + liquid_tip.time + + (chain_swap + .timeout_block_height + .saturating_sub(liquid_tip.height) + * ESTIMATED_LIQUID_BLOCK_TIME_SEC), + ); + } chain_swap.server_lockup_tx_id = recovered_data .btc_server_lockup_tx_id .clone() diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs index 2ebe663cf..f193a402f 100644 --- a/lib/core/src/sdk.rs +++ b/lib/core/src/sdk.rs @@ -6,8 +6,10 @@ use std::{fs, path::PathBuf, str::FromStr, sync::Arc, time::Duration}; use anyhow::{anyhow, Result}; use boltz_client::{swaps::boltz::*, util::secrets::Preimage}; use buy::{BuyBitcoinApi, BuyBitcoinService}; -use chain::bitcoin::HybridBitcoinChainService; -use chain::liquid::{HybridLiquidChainService, LiquidChainService}; +use chain::bitcoin::{HybridBitcoinChainService, ESTIMATED_BITCOIN_BLOCK_TIME_SEC}; +use chain::liquid::{ + HybridLiquidChainService, LiquidChainService, ESTIMATED_LIQUID_BLOCK_TIME_SEC, +}; use chain_swap::ESTIMATED_BTC_CLAIM_TX_VSIZE; use futures_util::stream::select_all; use futures_util::{StreamExt, TryFutureExt}; @@ -355,7 +357,7 @@ impl LiquidSdk { tokio::select! { _ = interval.tick() => { // Get the Liquid tip and process a new block - let liquid_tip_res = cloned.liquid_chain_service.lock().await.tip().await; + let liquid_tip_res = cloned.liquid_chain_service.lock().await.tip().await.map(|tip| tip.height); let is_new_liquid_block = match liquid_tip_res { Ok(height) => { debug!("Got Liquid tip: {height}"); @@ -1328,6 +1330,12 @@ impl LiquidSdk { let create_response_json = SendSwap::from_boltz_struct_to_json(&create_response, swap_id)?; + let liquid_tip = self.liquid_chain_service.lock().await.tip().await?; + let expiry_at = liquid_tip.time + + ((create_response.timeout_block_height as u32) + .saturating_sub(liquid_tip.height) + * ESTIMATED_LIQUID_BLOCK_TIME_SEC); + let payer_amount_sat = fees_sat + receiver_amount_sat; let swap = SendSwap { id: swap_id.clone(), @@ -1345,6 +1353,7 @@ impl LiquidSdk { lockup_tx_id: None, refund_tx_id: None, created_at: utils::now(), + expiry_at: Some(expiry_at), state: PaymentState::Created, refund_private_key: keypair.display_secret().to_string(), }; @@ -1606,6 +1615,14 @@ impl LiquidSdk { ChainSwap::from_boltz_struct_to_json(&create_response, &create_response.id)?; let swap_id = create_response.id; + let liquid_tip = self.liquid_chain_service.lock().await.tip().await?; + let expiry_at = liquid_tip.time + + (create_response + .lockup_details + .timeout_block_height + .saturating_sub(liquid_tip.height) + * ESTIMATED_LIQUID_BLOCK_TIME_SEC); + let accept_zero_conf = server_lockup_amount_sat <= pair.limits.maximal_zero_conf; let payer_amount_sat = req.prepare_response.total_fees_sat + receiver_amount_sat; @@ -1632,6 +1649,7 @@ impl LiquidSdk { claim_tx_id: None, refund_tx_id: None, created_at: utils::now(), + expiry_at: Some(expiry_at), state: PaymentState::Created, }; self.persister.insert_or_update_chain_swap(&swap)?; @@ -1957,6 +1975,14 @@ impl LiquidSdk { Bolt11InvoiceDescription::Direct(msg) => Some(msg.to_string()), Bolt11InvoiceDescription::Hash(_) => None, }; + + let liquid_tip = self.liquid_chain_service.lock().await.tip().await?; + let expiry_at = liquid_tip.time + + (create_response + .timeout_block_height + .saturating_sub(liquid_tip.height) + * ESTIMATED_LIQUID_BLOCK_TIME_SEC); + self.persister .insert_or_update_receive_swap(&ReceiveSwap { id: swap_id.clone(), @@ -1977,6 +2003,7 @@ impl LiquidSdk { mrh_address: mrh_addr_str, mrh_tx_id: None, created_at: utils::now(), + expiry_at: Some(expiry_at), state: PaymentState::Created, }) .map_err(|_| PaymentError::PersistError)?; @@ -2044,6 +2071,14 @@ impl LiquidSdk { let create_response_json = ChainSwap::from_boltz_struct_to_json(&create_response, &swap_id)?; + let bitcoin_tip = self.bitcoin_chain_service.lock().await.tip()?; + let expiry_at = bitcoin_tip.header.time + + (create_response + .lockup_details + .timeout_block_height + .saturating_sub(bitcoin_tip.height as u32) + * ESTIMATED_BITCOIN_BLOCK_TIME_SEC); + let accept_zero_conf = user_lockup_amount_sat .map(|user_lockup_amount_sat| user_lockup_amount_sat <= pair.limits.maximal_zero_conf) .unwrap_or(false); @@ -2074,6 +2109,7 @@ impl LiquidSdk { claim_tx_id: None, refund_tx_id: None, created_at: utils::now(), + expiry_at: Some(expiry_at), state: PaymentState::Created, }; self.persister.insert_or_update_chain_swap(&swap)?; @@ -2311,7 +2347,7 @@ impl LiquidSdk { match partial_sync { false => { let bitcoin_height = self.bitcoin_chain_service.lock().await.tip()?.height as u32; - let liquid_height = self.liquid_chain_service.lock().await.tip().await?; + let liquid_height = self.liquid_chain_service.lock().await.tip().await?.height; let final_swap_states = [PaymentState::Complete, PaymentState::Failed]; let send_swaps = self diff --git a/lib/core/src/sync/model/data.rs b/lib/core/src/sync/model/data.rs index cdd681884..8f434ba21 100644 --- a/lib/core/src/sync/model/data.rs +++ b/lib/core/src/sync/model/data.rs @@ -23,6 +23,8 @@ pub(crate) struct ChainSyncData { pub(crate) receiver_amount_sat: u64, pub(crate) accept_zero_conf: bool, pub(crate) created_at: u32, + #[serde(default)] + pub(crate) expiry_at: Option, pub(crate) description: Option, } @@ -33,6 +35,7 @@ impl ChainSyncData { "payer_amount_sat" => self.payer_amount_sat = other.payer_amount_sat, "receiver_amount_sat" => self.receiver_amount_sat = other.receiver_amount_sat, "accept_zero_conf" => self.accept_zero_conf = other.accept_zero_conf, + "expiry_at" => clone_if_set(&mut self.expiry_at, &other.expiry_at), _ => continue, } } @@ -56,6 +59,7 @@ impl From for ChainSyncData { receiver_amount_sat: value.receiver_amount_sat, accept_zero_conf: value.accept_zero_conf, created_at: value.created_at, + expiry_at: value.expiry_at, description: value.description, } } @@ -77,6 +81,7 @@ impl From for ChainSwap { pair_fees_json: val.pair_fees_json, create_response_json: val.create_response_json, created_at: val.created_at, + expiry_at: val.expiry_at, claim_private_key: val.claim_private_key, refund_private_key: val.refund_private_key, state: PaymentState::Created, @@ -99,6 +104,8 @@ pub(crate) struct SendSyncData { pub(crate) payer_amount_sat: u64, pub(crate) receiver_amount_sat: u64, pub(crate) created_at: u32, + #[serde(default)] + pub(crate) expiry_at: Option, pub(crate) preimage: Option, pub(crate) bolt12_offer: Option, pub(crate) payment_hash: Option, @@ -110,6 +117,7 @@ impl SendSyncData { for field in updated_fields { match field.as_str() { "preimage" => clone_if_set(&mut self.preimage, &other.preimage), + "expiry_at" => clone_if_set(&mut self.expiry_at, &other.expiry_at), _ => continue, } } @@ -128,6 +136,7 @@ impl From for SendSyncData { payer_amount_sat: value.payer_amount_sat, receiver_amount_sat: value.receiver_amount_sat, created_at: value.created_at, + expiry_at: value.expiry_at, preimage: value.preimage, description: value.description, bolt12_offer: value.bolt12_offer, @@ -148,6 +157,7 @@ impl From for SendSwap { pair_fees_json: val.pair_fees_json, create_response_json: val.create_response_json, created_at: val.created_at, + expiry_at: val.expiry_at, refund_private_key: val.refund_private_key, bolt12_offer: val.bolt12_offer, state: PaymentState::Created, @@ -170,10 +180,23 @@ pub(crate) struct ReceiveSyncData { pub(crate) receiver_amount_sat: u64, pub(crate) mrh_address: String, pub(crate) created_at: u32, + #[serde(default)] + pub(crate) expiry_at: Option, pub(crate) payment_hash: Option, pub(crate) description: Option, } +impl ReceiveSyncData { + pub(crate) fn merge(&mut self, other: &Self, updated_fields: &[String]) { + for field in updated_fields { + match field.as_str() { + "expiry_at" => clone_if_set(&mut self.expiry_at, &other.expiry_at), + _ => continue, + } + } + } +} + impl From for ReceiveSyncData { fn from(value: ReceiveSwap) -> Self { Self { @@ -189,6 +212,7 @@ impl From for ReceiveSyncData { receiver_amount_sat: value.receiver_amount_sat, mrh_address: value.mrh_address, created_at: value.created_at, + expiry_at: value.expiry_at, description: value.description, } } @@ -210,6 +234,7 @@ impl From for ReceiveSwap { claim_fees_sat: val.claim_fees_sat, mrh_address: val.mrh_address, created_at: val.created_at, + expiry_at: val.expiry_at, state: PaymentState::Created, claim_tx_id: None, lockup_tx_id: None, @@ -302,8 +327,8 @@ impl SyncData { (SyncData::Send(ref mut base), SyncData::Send(other)) => { base.merge(other, updated_fields) } - (SyncData::Receive(ref mut _base), SyncData::Receive(_other)) => { - log::warn!("Attempting to merge for unnecessary type SyncData::Receive"); + (SyncData::Receive(ref mut base), SyncData::Receive(other)) => { + base.merge(other, updated_fields) } ( SyncData::LastDerivationIndex(our_index), diff --git a/lib/core/src/test_utils/chain.rs b/lib/core/src/test_utils/chain.rs index 0a0073d58..17085893c 100644 --- a/lib/core/src/test_utils/chain.rs +++ b/lib/core/src/test_utils/chain.rs @@ -16,7 +16,8 @@ use electrum_client::{ }; use lwk_wollet::{ bitcoin::constants::genesis_block, - elements::{BlockHash, Txid as ElementsTxid}, + elements::{BlockHash, BlockHeader, TxMerkleNode, Txid as ElementsTxid}, + hashes::Hash, History, }; @@ -63,8 +64,17 @@ impl MockLiquidChainService { #[async_trait] impl LiquidChainService for MockLiquidChainService { - async fn tip(&mut self) -> Result { - Ok(0) + async fn tip(&mut self) -> Result { + let block_enc = BlockHash::engine(); + let merkle_enc = TxMerkleNode::engine(); + Ok(BlockHeader { + version: 0, + prev_blockhash: BlockHash::from_engine(block_enc), + merkle_root: TxMerkleNode::from_engine(merkle_enc), + time: 0, + height: 0, + ext: Default::default(), + }) } async fn broadcast( diff --git a/lib/core/src/test_utils/chain_swap.rs b/lib/core/src/test_utils/chain_swap.rs index 82467d10f..95fe8d372 100644 --- a/lib/core/src/test_utils/chain_swap.rs +++ b/lib/core/src/test_utils/chain_swap.rs @@ -111,6 +111,7 @@ pub(crate) fn new_chain_swap( claim_tx_id: None, refund_tx_id: None, created_at: utils::now(), + expiry_at: Some(utils::now() + 604800), state: payment_state.unwrap_or(PaymentState::Created), accept_zero_conf, pair_fees_json: r#"{ @@ -193,6 +194,7 @@ pub(crate) fn new_chain_swap( claim_tx_id: None, refund_tx_id: None, created_at: utils::now(), + expiry_at: Some(utils::now() + 604800), state: payment_state.unwrap_or(PaymentState::Created), accept_zero_conf, pair_fees_json: r#"{ diff --git a/lib/core/src/test_utils/persist.rs b/lib/core/src/test_utils/persist.rs index 6bdf1927b..6340fa57e 100644 --- a/lib/core/src/test_utils/persist.rs +++ b/lib/core/src/test_utils/persist.rs @@ -80,6 +80,7 @@ pub(crate) fn new_send_swap(payment_state: Option) -> SendSwap { lockup_tx_id: None, refund_tx_id: None, created_at: utils::now(), + expiry_at: Some(utils::now() + 86400), state: payment_state.unwrap_or(PaymentState::Created), refund_private_key: "945affeef55f12227f1d4a3f80a17062a05b229ddc5a01591eb5ddf882df92e3".to_string(), } @@ -133,6 +134,7 @@ pub(crate) fn new_receive_swap(payment_state: Option) -> ReceiveSw mrh_address: "tlq1pq2amlulhea6ltq7x3eu9atsc2nnrer7yt7xve363zxedqwu2mk6ctcyv9awl8xf28cythreqklt5q0qqwsxzlm6wu4z6d574adl9zh2zmr0h85gt534n".to_string(), mrh_tx_id: None, created_at: utils::now(), + expiry_at: Some(utils::now() + 86400), state: payment_state.unwrap_or(PaymentState::Created), } } diff --git a/lib/core/src/test_utils/sync.rs b/lib/core/src/test_utils/sync.rs index a4ab84e3a..b7aea1397 100644 --- a/lib/core/src/test_utils/sync.rs +++ b/lib/core/src/test_utils/sync.rs @@ -121,6 +121,7 @@ pub(crate) fn new_receive_sync_data() -> ReceiveSyncData { payer_amount_sat: 0, receiver_amount_sat: 0, created_at: 0, + expiry_at: None, claim_fees_sat: 0, claim_private_key: "".to_string(), mrh_address: "".to_string(), @@ -140,6 +141,7 @@ pub(crate) fn new_send_sync_data(preimage: Option) -> SendSyncData { payer_amount_sat: 0, receiver_amount_sat: 0, created_at: 0, + expiry_at: None, preimage, payment_hash: None, description: None, @@ -163,6 +165,7 @@ pub(crate) fn new_chain_sync_data(accept_zero_conf: Option) -> ChainSyncDa receiver_amount_sat: 0, accept_zero_conf: accept_zero_conf.unwrap_or(true), created_at: 0, + expiry_at: None, description: None, } } diff --git a/packages/dart/lib/src/frb_generated.dart b/packages/dart/lib/src/frb_generated.dart index a02364a5e..98dd8d81f 100644 --- a/packages/dart/lib/src/frb_generated.dart +++ b/packages/dart/lib/src/frb_generated.dart @@ -2576,13 +2576,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return PaymentDetails_Lightning( swapId: dco_decode_String(raw[1]), description: dco_decode_String(raw[2]), - preimage: dco_decode_opt_String(raw[3]), - bolt11: dco_decode_opt_String(raw[4]), - bolt12Offer: dco_decode_opt_String(raw[5]), - paymentHash: dco_decode_opt_String(raw[6]), - lnurlInfo: dco_decode_opt_box_autoadd_ln_url_info(raw[7]), - refundTxId: dco_decode_opt_String(raw[8]), - refundTxAmountSat: dco_decode_opt_box_autoadd_u_64(raw[9]), + expiryTimestamp: dco_decode_opt_box_autoadd_u_32(raw[3]), + preimage: dco_decode_opt_String(raw[4]), + bolt11: dco_decode_opt_String(raw[5]), + bolt12Offer: dco_decode_opt_String(raw[6]), + paymentHash: dco_decode_opt_String(raw[7]), + lnurlInfo: dco_decode_opt_box_autoadd_ln_url_info(raw[8]), + refundTxId: dco_decode_opt_String(raw[9]), + refundTxAmountSat: dco_decode_opt_box_autoadd_u_64(raw[10]), ); case 1: return PaymentDetails_Liquid( @@ -2593,8 +2594,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return PaymentDetails_Bitcoin( swapId: dco_decode_String(raw[1]), description: dco_decode_String(raw[2]), - refundTxId: dco_decode_opt_String(raw[3]), - refundTxAmountSat: dco_decode_opt_box_autoadd_u_64(raw[4]), + expiryTimestamp: dco_decode_opt_box_autoadd_u_32(raw[3]), + refundTxId: dco_decode_opt_String(raw[4]), + refundTxAmountSat: dco_decode_opt_box_autoadd_u_64(raw[5]), ); default: throw Exception("unreachable"); @@ -4679,6 +4681,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { case 0: var var_swapId = sse_decode_String(deserializer); var var_description = sse_decode_String(deserializer); + var var_expiryTimestamp = sse_decode_opt_box_autoadd_u_32(deserializer); var var_preimage = sse_decode_opt_String(deserializer); var var_bolt11 = sse_decode_opt_String(deserializer); var var_bolt12Offer = sse_decode_opt_String(deserializer); @@ -4689,6 +4692,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return PaymentDetails_Lightning( swapId: var_swapId, description: var_description, + expiryTimestamp: var_expiryTimestamp, preimage: var_preimage, bolt11: var_bolt11, bolt12Offer: var_bolt12Offer, @@ -4703,11 +4707,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { case 2: var var_swapId = sse_decode_String(deserializer); var var_description = sse_decode_String(deserializer); + var var_expiryTimestamp = 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, + expiryTimestamp: var_expiryTimestamp, refundTxId: var_refundTxId, refundTxAmountSat: var_refundTxAmountSat); default: @@ -6637,6 +6643,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { case PaymentDetails_Lightning( swapId: final swapId, description: final description, + expiryTimestamp: final expiryTimestamp, preimage: final preimage, bolt11: final bolt11, bolt12Offer: final bolt12Offer, @@ -6648,6 +6655,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_i_32(0, serializer); sse_encode_String(swapId, serializer); sse_encode_String(description, serializer); + sse_encode_opt_box_autoadd_u_32(expiryTimestamp, serializer); sse_encode_opt_String(preimage, serializer); sse_encode_opt_String(bolt11, serializer); sse_encode_opt_String(bolt12Offer, serializer); @@ -6662,12 +6670,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { case PaymentDetails_Bitcoin( swapId: final swapId, description: final description, + expiryTimestamp: final expiryTimestamp, refundTxId: final refundTxId, refundTxAmountSat: final refundTxAmountSat ): sse_encode_i_32(2, serializer); sse_encode_String(swapId, serializer); sse_encode_String(description, serializer); + sse_encode_opt_box_autoadd_u_32(expiryTimestamp, serializer); sse_encode_opt_String(refundTxId, serializer); sse_encode_opt_box_autoadd_u_64(refundTxAmountSat, serializer); default: diff --git a/packages/dart/lib/src/frb_generated.io.dart b/packages/dart/lib/src/frb_generated.io.dart index 7bbf04c83..9f5a5e7fc 100644 --- a/packages/dart/lib/src/frb_generated.io.dart +++ b/packages/dart/lib/src/frb_generated.io.dart @@ -2837,6 +2837,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { if (apiObj is PaymentDetails_Lightning) { var pre_swap_id = cst_encode_String(apiObj.swapId); var pre_description = cst_encode_String(apiObj.description); + var pre_expiry_timestamp = cst_encode_opt_box_autoadd_u_32(apiObj.expiryTimestamp); var pre_preimage = cst_encode_opt_String(apiObj.preimage); var pre_bolt11 = cst_encode_opt_String(apiObj.bolt11); var pre_bolt12_offer = cst_encode_opt_String(apiObj.bolt12Offer); @@ -2847,6 +2848,7 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { wireObj.tag = 0; wireObj.kind.Lightning.swap_id = pre_swap_id; wireObj.kind.Lightning.description = pre_description; + wireObj.kind.Lightning.expiry_timestamp = pre_expiry_timestamp; wireObj.kind.Lightning.preimage = pre_preimage; wireObj.kind.Lightning.bolt11 = pre_bolt11; wireObj.kind.Lightning.bolt12_offer = pre_bolt12_offer; @@ -2867,11 +2869,13 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { if (apiObj is PaymentDetails_Bitcoin) { var pre_swap_id = cst_encode_String(apiObj.swapId); var pre_description = cst_encode_String(apiObj.description); + var pre_expiry_timestamp = cst_encode_opt_box_autoadd_u_32(apiObj.expiryTimestamp); var pre_refund_tx_id = cst_encode_opt_String(apiObj.refundTxId); var pre_refund_tx_amount_sat = cst_encode_opt_box_autoadd_u_64(apiObj.refundTxAmountSat); wireObj.tag = 2; wireObj.kind.Bitcoin.swap_id = pre_swap_id; wireObj.kind.Bitcoin.description = pre_description; + wireObj.kind.Bitcoin.expiry_timestamp = pre_expiry_timestamp; wireObj.kind.Bitcoin.refund_tx_id = pre_refund_tx_id; wireObj.kind.Bitcoin.refund_tx_amount_sat = pre_refund_tx_amount_sat; return; @@ -6124,6 +6128,8 @@ final class wire_cst_PaymentDetails_Lightning extends ffi.Struct { external ffi.Pointer description; + external ffi.Pointer expiry_timestamp; + external ffi.Pointer preimage; external ffi.Pointer bolt11; @@ -6150,6 +6156,8 @@ final class wire_cst_PaymentDetails_Bitcoin extends ffi.Struct { external ffi.Pointer description; + external ffi.Pointer expiry_timestamp; + external ffi.Pointer refund_tx_id; external ffi.Pointer refund_tx_amount_sat; diff --git a/packages/dart/lib/src/model.dart b/packages/dart/lib/src/model.dart index 1e5b7924f..1f21077b4 100644 --- a/packages/dart/lib/src/model.dart +++ b/packages/dart/lib/src/model.dart @@ -691,7 +691,10 @@ sealed class PaymentDetails with _$PaymentDetails { /// Represents the invoice description required String description, - /// In case of a Send swap, this is the preimage of the paid invoice (proof of payment). + /// The estimated swap expiry + int? expiryTimestamp, + + /// The preimage of the paid invoice (proof of payment). String? preimage, /// Represents the Bolt11 invoice associated with a payment @@ -729,6 +732,9 @@ sealed class PaymentDetails with _$PaymentDetails { /// Represents the invoice description required String description, + /// The estimated swap expiry + int? expiryTimestamp, + /// For a Send swap which was refunded, this is the refund tx id String? refundTxId, diff --git a/packages/dart/lib/src/model.freezed.dart b/packages/dart/lib/src/model.freezed.dart index a712d5559..8a8114f30 100644 --- a/packages/dart/lib/src/model.freezed.dart +++ b/packages/dart/lib/src/model.freezed.dart @@ -791,6 +791,7 @@ abstract class _$$PaymentDetails_LightningImplCopyWith<$Res> implements $Payment $Res call( {String swapId, String description, + int? expiryTimestamp, String? preimage, String? bolt11, String? bolt12Offer, @@ -815,6 +816,7 @@ class __$$PaymentDetails_LightningImplCopyWithImpl<$Res> $Res call({ Object? swapId = null, Object? description = null, + Object? expiryTimestamp = freezed, Object? preimage = freezed, Object? bolt11 = freezed, Object? bolt12Offer = freezed, @@ -832,6 +834,10 @@ class __$$PaymentDetails_LightningImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, + expiryTimestamp: freezed == expiryTimestamp + ? _value.expiryTimestamp + : expiryTimestamp // ignore: cast_nullable_to_non_nullable + as int?, preimage: freezed == preimage ? _value.preimage : preimage // ignore: cast_nullable_to_non_nullable @@ -870,6 +876,7 @@ class _$PaymentDetails_LightningImpl extends PaymentDetails_Lightning { const _$PaymentDetails_LightningImpl( {required this.swapId, required this.description, + this.expiryTimestamp, this.preimage, this.bolt11, this.bolt12Offer, @@ -886,7 +893,11 @@ class _$PaymentDetails_LightningImpl extends PaymentDetails_Lightning { @override final String description; - /// In case of a Send swap, this is the preimage of the paid invoice (proof of payment). + /// The estimated swap expiry + @override + final int? expiryTimestamp; + + /// The preimage of the paid invoice (proof of payment). @override final String? preimage; @@ -916,7 +927,7 @@ class _$PaymentDetails_LightningImpl extends PaymentDetails_Lightning { @override String toString() { - return 'PaymentDetails.lightning(swapId: $swapId, description: $description, preimage: $preimage, bolt11: $bolt11, bolt12Offer: $bolt12Offer, paymentHash: $paymentHash, lnurlInfo: $lnurlInfo, refundTxId: $refundTxId, refundTxAmountSat: $refundTxAmountSat)'; + return 'PaymentDetails.lightning(swapId: $swapId, description: $description, expiryTimestamp: $expiryTimestamp, preimage: $preimage, bolt11: $bolt11, bolt12Offer: $bolt12Offer, paymentHash: $paymentHash, lnurlInfo: $lnurlInfo, refundTxId: $refundTxId, refundTxAmountSat: $refundTxAmountSat)'; } @override @@ -926,6 +937,7 @@ class _$PaymentDetails_LightningImpl extends PaymentDetails_Lightning { other is _$PaymentDetails_LightningImpl && (identical(other.swapId, swapId) || other.swapId == swapId) && (identical(other.description, description) || other.description == description) && + (identical(other.expiryTimestamp, expiryTimestamp) || other.expiryTimestamp == expiryTimestamp) && (identical(other.preimage, preimage) || other.preimage == preimage) && (identical(other.bolt11, bolt11) || other.bolt11 == bolt11) && (identical(other.bolt12Offer, bolt12Offer) || other.bolt12Offer == bolt12Offer) && @@ -937,8 +949,8 @@ class _$PaymentDetails_LightningImpl extends PaymentDetails_Lightning { } @override - int get hashCode => Object.hash(runtimeType, swapId, description, preimage, bolt11, bolt12Offer, - paymentHash, lnurlInfo, refundTxId, refundTxAmountSat); + int get hashCode => Object.hash(runtimeType, swapId, description, expiryTimestamp, preimage, bolt11, + bolt12Offer, paymentHash, lnurlInfo, refundTxId, refundTxAmountSat); /// Create a copy of PaymentDetails /// with the given fields replaced by the non-null parameter values. @@ -953,6 +965,7 @@ abstract class PaymentDetails_Lightning extends PaymentDetails { const factory PaymentDetails_Lightning( {required final String swapId, required final String description, + final int? expiryTimestamp, final String? preimage, final String? bolt11, final String? bolt12Offer, @@ -968,7 +981,10 @@ abstract class PaymentDetails_Lightning extends PaymentDetails { @override String get description; - /// In case of a Send swap, this is the preimage of the paid invoice (proof of payment). + /// The estimated swap expiry + int? get expiryTimestamp; + + /// The preimage of the paid invoice (proof of payment). String? get preimage; /// Represents the Bolt11 invoice associated with a payment @@ -1102,7 +1118,12 @@ abstract class _$$PaymentDetails_BitcoinImplCopyWith<$Res> implements $PaymentDe __$$PaymentDetails_BitcoinImplCopyWithImpl<$Res>; @override @useResult - $Res call({String swapId, String description, String? refundTxId, BigInt? refundTxAmountSat}); + $Res call( + {String swapId, + String description, + int? expiryTimestamp, + String? refundTxId, + BigInt? refundTxAmountSat}); } /// @nodoc @@ -1120,6 +1141,7 @@ class __$$PaymentDetails_BitcoinImplCopyWithImpl<$Res> $Res call({ Object? swapId = null, Object? description = null, + Object? expiryTimestamp = freezed, Object? refundTxId = freezed, Object? refundTxAmountSat = freezed, }) { @@ -1132,6 +1154,10 @@ class __$$PaymentDetails_BitcoinImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, + expiryTimestamp: freezed == expiryTimestamp + ? _value.expiryTimestamp + : expiryTimestamp // ignore: cast_nullable_to_non_nullable + as int?, refundTxId: freezed == refundTxId ? _value.refundTxId : refundTxId // ignore: cast_nullable_to_non_nullable @@ -1148,7 +1174,11 @@ class __$$PaymentDetails_BitcoinImplCopyWithImpl<$Res> class _$PaymentDetails_BitcoinImpl extends PaymentDetails_Bitcoin { const _$PaymentDetails_BitcoinImpl( - {required this.swapId, required this.description, this.refundTxId, this.refundTxAmountSat}) + {required this.swapId, + required this.description, + this.expiryTimestamp, + this.refundTxId, + this.refundTxAmountSat}) : super._(); @override @@ -1158,6 +1188,10 @@ class _$PaymentDetails_BitcoinImpl extends PaymentDetails_Bitcoin { @override final String description; + /// The estimated swap expiry + @override + final int? expiryTimestamp; + /// For a Send swap which was refunded, this is the refund tx id @override final String? refundTxId; @@ -1168,7 +1202,7 @@ class _$PaymentDetails_BitcoinImpl extends PaymentDetails_Bitcoin { @override String toString() { - return 'PaymentDetails.bitcoin(swapId: $swapId, description: $description, refundTxId: $refundTxId, refundTxAmountSat: $refundTxAmountSat)'; + return 'PaymentDetails.bitcoin(swapId: $swapId, description: $description, expiryTimestamp: $expiryTimestamp, refundTxId: $refundTxId, refundTxAmountSat: $refundTxAmountSat)'; } @override @@ -1178,13 +1212,15 @@ class _$PaymentDetails_BitcoinImpl extends PaymentDetails_Bitcoin { other is _$PaymentDetails_BitcoinImpl && (identical(other.swapId, swapId) || other.swapId == swapId) && (identical(other.description, description) || other.description == description) && + (identical(other.expiryTimestamp, expiryTimestamp) || other.expiryTimestamp == expiryTimestamp) && (identical(other.refundTxId, refundTxId) || other.refundTxId == refundTxId) && (identical(other.refundTxAmountSat, refundTxAmountSat) || other.refundTxAmountSat == refundTxAmountSat)); } @override - int get hashCode => Object.hash(runtimeType, swapId, description, refundTxId, refundTxAmountSat); + int get hashCode => + Object.hash(runtimeType, swapId, description, expiryTimestamp, refundTxId, refundTxAmountSat); /// Create a copy of PaymentDetails /// with the given fields replaced by the non-null parameter values. @@ -1199,6 +1235,7 @@ abstract class PaymentDetails_Bitcoin extends PaymentDetails { const factory PaymentDetails_Bitcoin( {required final String swapId, required final String description, + final int? expiryTimestamp, final String? refundTxId, final BigInt? refundTxAmountSat}) = _$PaymentDetails_BitcoinImpl; const PaymentDetails_Bitcoin._() : super._(); @@ -1209,6 +1246,9 @@ abstract class PaymentDetails_Bitcoin extends PaymentDetails { @override String get description; + /// The estimated swap expiry + int? get expiryTimestamp; + /// For a Send swap which was refunded, this is the refund tx id String? get refundTxId; diff --git a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart index 45c6ce4c2..73190ca08 100644 --- a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart +++ b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart @@ -4545,6 +4545,8 @@ final class wire_cst_PaymentDetails_Lightning extends ffi.Struct { external ffi.Pointer description; + external ffi.Pointer expiry_timestamp; + external ffi.Pointer preimage; external ffi.Pointer bolt11; @@ -4571,6 +4573,8 @@ final class wire_cst_PaymentDetails_Bitcoin extends ffi.Struct { external ffi.Pointer description; + external ffi.Pointer expiry_timestamp; + external ffi.Pointer refund_tx_id; external ffi.Pointer refund_tx_amount_sat; diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt index 3cfb3c54e..8fd3df9fb 100644 --- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt +++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt @@ -3059,6 +3059,16 @@ fun asPaymentDetails(paymentDetails: ReadableMap): PaymentDetails? { if (type == "lightning") { val swapId = paymentDetails.getString("swapId")!! val description = paymentDetails.getString("description")!! + val expiryTimestamp = + if (hasNonNullKey( + paymentDetails, + "expiryTimestamp", + ) + ) { + paymentDetails.getInt("expiryTimestamp").toUInt() + } else { + null + } val preimage = if (hasNonNullKey(paymentDetails, "preimage")) paymentDetails.getString("preimage") else null val bolt11 = if (hasNonNullKey(paymentDetails, "bolt11")) paymentDetails.getString("bolt11") else null val bolt12Offer = if (hasNonNullKey(paymentDetails, "bolt12Offer")) paymentDetails.getString("bolt12Offer") else null @@ -3087,6 +3097,7 @@ fun asPaymentDetails(paymentDetails: ReadableMap): PaymentDetails? { return PaymentDetails.Lightning( swapId, description, + expiryTimestamp, preimage, bolt11, bolt12Offer, @@ -3104,6 +3115,16 @@ fun asPaymentDetails(paymentDetails: ReadableMap): PaymentDetails? { if (type == "bitcoin") { val swapId = paymentDetails.getString("swapId")!! val description = paymentDetails.getString("description")!! + val expiryTimestamp = + if (hasNonNullKey( + paymentDetails, + "expiryTimestamp", + ) + ) { + paymentDetails.getInt("expiryTimestamp").toUInt() + } else { + null + } val refundTxId = if (hasNonNullKey(paymentDetails, "refundTxId")) paymentDetails.getString("refundTxId") else null val refundTxAmountSat = if (hasNonNullKey( @@ -3115,7 +3136,7 @@ fun asPaymentDetails(paymentDetails: ReadableMap): PaymentDetails? { } else { null } - return PaymentDetails.Bitcoin(swapId, description, refundTxId, refundTxAmountSat) + return PaymentDetails.Bitcoin(swapId, description, expiryTimestamp, refundTxId, refundTxAmountSat) } return null } @@ -3127,6 +3148,7 @@ fun readableMapOf(paymentDetails: PaymentDetails): ReadableMap? { pushToMap(map, "type", "lightning") pushToMap(map, "swapId", paymentDetails.swapId) pushToMap(map, "description", paymentDetails.description) + pushToMap(map, "expiryTimestamp", paymentDetails.expiryTimestamp) pushToMap(map, "preimage", paymentDetails.preimage) pushToMap(map, "bolt11", paymentDetails.bolt11) pushToMap(map, "bolt12Offer", paymentDetails.bolt12Offer) @@ -3144,6 +3166,7 @@ fun readableMapOf(paymentDetails: PaymentDetails): ReadableMap? { pushToMap(map, "type", "bitcoin") pushToMap(map, "swapId", paymentDetails.swapId) pushToMap(map, "description", paymentDetails.description) + pushToMap(map, "expiryTimestamp", paymentDetails.expiryTimestamp) pushToMap(map, "refundTxId", paymentDetails.refundTxId) pushToMap(map, "refundTxAmountSat", paymentDetails.refundTxAmountSat) } diff --git a/packages/react-native/ios/BreezSDKLiquidMapper.swift b/packages/react-native/ios/BreezSDKLiquidMapper.swift index 3e3bb72e6..0424dd988 100644 --- a/packages/react-native/ios/BreezSDKLiquidMapper.swift +++ b/packages/react-native/ios/BreezSDKLiquidMapper.swift @@ -3748,6 +3748,8 @@ enum BreezSDKLiquidMapper { guard let _description = paymentDetails["description"] as? String else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "description", typeName: "PaymentDetails")) } + let _expiryTimestamp = paymentDetails["expiryTimestamp"] as? UInt32 + let _preimage = paymentDetails["preimage"] as? String let _bolt11 = paymentDetails["bolt11"] as? String @@ -3765,7 +3767,7 @@ enum BreezSDKLiquidMapper { let _refundTxAmountSat = paymentDetails["refundTxAmountSat"] as? UInt64 - return PaymentDetails.lightning(swapId: _swapId, description: _description, preimage: _preimage, bolt11: _bolt11, bolt12Offer: _bolt12Offer, paymentHash: _paymentHash, lnurlInfo: _lnurlInfo, refundTxId: _refundTxId, refundTxAmountSat: _refundTxAmountSat) + return PaymentDetails.lightning(swapId: _swapId, description: _description, expiryTimestamp: _expiryTimestamp, preimage: _preimage, bolt11: _bolt11, bolt12Offer: _bolt12Offer, paymentHash: _paymentHash, lnurlInfo: _lnurlInfo, refundTxId: _refundTxId, refundTxAmountSat: _refundTxAmountSat) } if type == "liquid" { guard let _destination = paymentDetails["destination"] as? String else { @@ -3783,11 +3785,13 @@ enum BreezSDKLiquidMapper { guard let _description = paymentDetails["description"] as? String else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "description", typeName: "PaymentDetails")) } + let _expiryTimestamp = paymentDetails["expiryTimestamp"] as? UInt32 + let _refundTxId = paymentDetails["refundTxId"] as? String let _refundTxAmountSat = paymentDetails["refundTxAmountSat"] as? UInt64 - return PaymentDetails.bitcoin(swapId: _swapId, description: _description, refundTxId: _refundTxId, refundTxAmountSat: _refundTxAmountSat) + return PaymentDetails.bitcoin(swapId: _swapId, description: _description, expiryTimestamp: _expiryTimestamp, refundTxId: _refundTxId, refundTxAmountSat: _refundTxAmountSat) } throw SdkError.Generic(message: "Unexpected type \(type) for enum PaymentDetails") @@ -3796,12 +3800,13 @@ enum BreezSDKLiquidMapper { static func dictionaryOf(paymentDetails: PaymentDetails) -> [String: Any?] { switch paymentDetails { case let .lightning( - swapId, description, preimage, bolt11, bolt12Offer, paymentHash, lnurlInfo, refundTxId, refundTxAmountSat + swapId, description, expiryTimestamp, preimage, bolt11, bolt12Offer, paymentHash, lnurlInfo, refundTxId, refundTxAmountSat ): return [ "type": "lightning", "swapId": swapId, "description": description, + "expiryTimestamp": expiryTimestamp == nil ? nil : expiryTimestamp, "preimage": preimage == nil ? nil : preimage, "bolt11": bolt11 == nil ? nil : bolt11, "bolt12Offer": bolt12Offer == nil ? nil : bolt12Offer, @@ -3821,12 +3826,13 @@ enum BreezSDKLiquidMapper { ] case let .bitcoin( - swapId, description, refundTxId, refundTxAmountSat + swapId, description, expiryTimestamp, refundTxId, refundTxAmountSat ): return [ "type": "bitcoin", "swapId": swapId, "description": description, + "expiryTimestamp": expiryTimestamp == nil ? nil : expiryTimestamp, "refundTxId": refundTxId == nil ? nil : refundTxId, "refundTxAmountSat": refundTxAmountSat == nil ? nil : refundTxAmountSat, ] diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts index 12f1e5921..9acda60a8 100644 --- a/packages/react-native/src/index.ts +++ b/packages/react-native/src/index.ts @@ -615,6 +615,7 @@ export type PaymentDetails = { type: PaymentDetailsVariant.LIGHTNING, swapId: string description: string + expiryTimestamp?: number preimage?: string bolt11?: string bolt12Offer?: string @@ -630,6 +631,7 @@ export type PaymentDetails = { type: PaymentDetailsVariant.BITCOIN, swapId: string description: string + expiryTimestamp?: number refundTxId?: string refundTxAmountSat?: number }