From a123d3265124bb6f0b5f80cc8c536a3574d70d88 Mon Sep 17 00:00:00 2001 From: yse <70684173+hydra-yse@users.noreply.github.com> Date: Thu, 21 Mar 2024 19:42:21 +0100 Subject: [PATCH] feat: added onchain_amount_sat field to received swaps (#41) --- cli/src/commands.rs | 22 +++++++++--- lib/src/lib.rs | 7 ++-- lib/src/model.rs | 18 +++++++++- lib/src/persist/migrations.rs | 3 +- lib/src/persist/mod.rs | 19 +++++----- lib/src/wallet.rs | 65 +++++++++++++++++++++++------------ 6 files changed, 95 insertions(+), 39 deletions(-) diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 4489fa0ac..3d6639630 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -2,20 +2,26 @@ use std::borrow::Cow::{self, Owned}; use std::sync::Arc; use anyhow::Result; -use clap::Parser; +use clap::{arg, Parser}; use rustyline::highlight::Highlighter; use rustyline::history::DefaultHistory; use rustyline::Editor; use rustyline::{hint::HistoryHinter, Completer, Helper, Hinter, Validator}; -use breez_sdk_liquid::Wallet; +use breez_sdk_liquid::{ReceivePaymentRequest, Wallet}; #[derive(Parser, Debug, Clone, PartialEq)] pub(crate) enum Command { /// Send lbtc and receive btc through a swap SendPayment { bolt11: String }, /// Receive lbtc and send btc through a swap - ReceivePayment { amount_sat: u64 }, + ReceivePayment { + #[arg(short, long)] + onchain_amount_sat: Option, + + #[arg(short, long)] + invoice_amount_sat: Option, + }, /// List incoming and outgoing payments ListPayments, /// Get the balance of the currently loaded wallet @@ -40,8 +46,14 @@ pub(crate) async fn handle_command( command: Command, ) -> Result { match command { - Command::ReceivePayment { amount_sat } => { - let response = wallet.receive_payment(amount_sat)?; + Command::ReceivePayment { + onchain_amount_sat, + invoice_amount_sat, + } => { + let response = wallet.receive_payment(ReceivePaymentRequest { + invoice_amount_sat, + onchain_amount_sat, + })?; dbg!(&response); Ok(format!( "Please pay the following invoice: {}", diff --git a/lib/src/lib.rs b/lib/src/lib.rs index f9d5a8f4c..066ee17d1 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -12,7 +12,7 @@ mod tests { use anyhow::Result; use bip39::{Language, Mnemonic}; - use crate::Wallet; + use crate::{ReceivePaymentRequest, Wallet}; const DEFAULT_DATA_DIR: &str = ".data"; const PHRASE_FILE_NAME: &str = "phrase"; @@ -58,7 +58,10 @@ mod tests { fn reverse_submarine_swap_success() -> Result<()> { let breez_wallet = Wallet::init(get_mnemonic()?.to_string())?; - let swap_response = breez_wallet.receive_payment(1000)?; + let swap_response = breez_wallet.receive_payment(ReceivePaymentRequest { + onchain_amount_sat: Some(1000), + invoice_amount_sat: None, + })?; println!( "Please pay the following invoice: {}", diff --git a/lib/src/model.rs b/lib/src/model.rs index d3639c182..baf72fada 100644 --- a/lib/src/model.rs +++ b/lib/src/model.rs @@ -51,6 +51,11 @@ impl ToString for SwapStatus { } } +pub struct ReceivePaymentRequest { + pub invoice_amount_sat: Option, + pub onchain_amount_sat: Option, +} + pub struct SendPaymentResponse { pub txid: String, } @@ -104,12 +109,23 @@ pub struct WalletInfo { pub active_address: String, } -pub struct OngoingSwap { +#[derive(Debug)] +pub struct OngoingReceiveSwap { pub id: String, pub preimage: String, pub redeem_script: String, pub blinding_key: String, pub invoice_amount_sat: u64, + pub onchain_amount_sat: u64, +} + +pub struct OngoingSendSwap { + pub id: String, + // pub preimage: String, + // pub redeem_script: String, + // pub blinding_key: String, + // pub invoice_amount_sat: Option, + // pub onchain_amount_sat: Option, } pub enum PaymentType { diff --git a/lib/src/persist/migrations.rs b/lib/src/persist/migrations.rs index 5c59612bc..3e95fa076 100644 --- a/lib/src/persist/migrations.rs +++ b/lib/src/persist/migrations.rs @@ -5,7 +5,8 @@ pub(crate) fn current_migrations() -> Vec<&'static str> { preimage TEXT NOT NULL, redeem_script TEXT NOT NULL, blinding_key TEXT NOT NULL, - invoice_amount_sat INTEGER + invoice_amount_sat INTEGER NOT NULL, + onchain_amount_sat INTEGER NOT NULL ) STRICT;", ] } diff --git a/lib/src/persist/mod.rs b/lib/src/persist/mod.rs index da3785c3e..54d60d70d 100644 --- a/lib/src/persist/mod.rs +++ b/lib/src/persist/mod.rs @@ -4,7 +4,7 @@ use anyhow::Result; use rusqlite::{params, Connection, Row}; use rusqlite_migration::{Migrations, M}; -use crate::OngoingSwap; +use crate::OngoingReceiveSwap; use migrations::current_migrations; @@ -35,7 +35,7 @@ impl Persister { Ok(()) } - pub fn insert_ongoing_swaps(&self, swaps: &[OngoingSwap]) -> Result<()> { + pub fn insert_ongoing_swaps(&self, swaps: &[OngoingReceiveSwap]) -> Result<()> { let con = self.get_connection()?; let mut stmt = con.prepare( @@ -45,9 +45,10 @@ impl Persister { preimage, redeem_script, blinding_key, - invoice_amount_sat + invoice_amount_sat, + onchain_amount_sat ) - VALUES (?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?) ", )?; @@ -58,6 +59,7 @@ impl Persister { &swap.redeem_script, &swap.blinding_key, &swap.invoice_amount_sat, + &swap.onchain_amount_sat, ))? } @@ -73,12 +75,12 @@ impl Persister { Ok(()) } - pub fn list_ongoing_swaps(&self) -> Result> { + pub fn list_ongoing_swaps(&self) -> Result> { let con = self.get_connection()?; let mut stmt = con.prepare("SELECT * FROM ongoing_swaps")?; - let swaps: Vec = stmt + let swaps: Vec = stmt .query_map(params![], |row| self.sql_row_to_swap(row))? .map(|i| i.unwrap()) .collect(); @@ -86,13 +88,14 @@ impl Persister { Ok(swaps) } - fn sql_row_to_swap(&self, row: &Row) -> Result { - Ok(OngoingSwap { + fn sql_row_to_swap(&self, row: &Row) -> Result { + Ok(OngoingReceiveSwap { id: row.get(0)?, preimage: row.get(1)?, redeem_script: row.get(2)?, blinding_key: row.get(3)?, invoice_amount_sat: row.get(4)?, + onchain_amount_sat: row.get(5)?, }) } } diff --git a/lib/src/wallet.rs b/lib/src/wallet.rs index 5dc652ed5..b755ca48e 100644 --- a/lib/src/wallet.rs +++ b/lib/src/wallet.rs @@ -23,8 +23,8 @@ use lwk_wollet::{ }; use crate::{ - persist::Persister, Network, OngoingSwap, Payment, PaymentType, SendPaymentResponse, SwapError, - SwapLbtcResponse, WalletInfo, WalletOptions, + persist::Persister, Network, OngoingReceiveSwap, Payment, PaymentType, ReceivePaymentRequest, + SendPaymentResponse, SwapError, SwapLbtcResponse, WalletInfo, WalletOptions, }; // To avoid sendrawtransaction error "min relay fee not met" @@ -107,7 +107,7 @@ impl Wallet { thread::scope(|scope| { for swap in ongoing_swaps { scope.spawn(|| { - let OngoingSwap { + let OngoingReceiveSwap { preimage, redeem_script, blinding_key, @@ -273,12 +273,18 @@ impl Wallet { )?; let txid = rev_swap_tx.broadcast(signed_tx, network_config)?; - debug!("Funds claimed successfully! Txid: {txid}"); - Ok(txid) } - pub fn receive_payment(&self, amount_sat: u64) -> Result { + pub fn receive_payment( + &self, + req: ReceivePaymentRequest, + ) -> Result { + let mut amount_sat = req + .onchain_amount_sat + .or(req.invoice_amount_sat) + .ok_or(SwapError::AmountOutOfRange)?; + let client = self.boltz_client(); let lbtc_pair = client.get_pairs()?.get_lbtc_pair()?; @@ -297,12 +303,22 @@ impl Wallet { let preimage_str = preimage.to_string().ok_or(SwapError::InvalidPreimage)?; let preimage_hash = preimage.sha256.to_string(); - let swap_response = client.create_swap(CreateSwapRequest::new_lbtc_reverse_invoice_amt( - lbtc_pair.hash, - preimage_hash.clone(), - lsk.keypair.public_key().to_string(), - amount_sat, - ))?; + let swap_response = if req.onchain_amount_sat.is_some() { + amount_sat += CLAIM_ABSOLUTE_FEES; + client.create_swap(CreateSwapRequest::new_lbtc_reverse_onchain_amt( + lbtc_pair.hash, + preimage_hash.clone(), + lsk.keypair.public_key().to_string(), + amount_sat, + ))? + } else { + client.create_swap(CreateSwapRequest::new_lbtc_reverse_invoice_amt( + lbtc_pair.hash, + preimage_hash.clone(), + lsk.keypair.public_key().to_string(), + amount_sat, + ))? + }; let swap_id = swap_response.get_id(); let invoice = swap_response.get_invoice()?; @@ -311,24 +327,29 @@ impl Wallet { // Double check that the generated invoice includes our data // https://docs.boltz.exchange/v/api/dont-trust-verify#lightning-invoice-verification - if invoice.payment_hash().to_string() != preimage_hash - || invoice - .amount_milli_satoshis() - .ok_or(SwapError::InvalidInvoice)? - / 1000 - != amount_sat - { + if invoice.payment_hash().to_string() != preimage_hash { return Err(SwapError::InvalidInvoice); }; + let invoice_amount_sat = invoice + .amount_milli_satoshis() + .ok_or(SwapError::InvalidInvoice)? + / 1000; + self.swap_persister - .insert_ongoing_swaps(&[OngoingSwap { + .insert_ongoing_swaps(dbg!(&[OngoingReceiveSwap { id: swap_id.clone(), preimage: preimage_str, blinding_key: blinding_str, redeem_script, - invoice_amount_sat: amount_sat, - }]) + invoice_amount_sat, + onchain_amount_sat: req.onchain_amount_sat.unwrap_or( + invoice_amount_sat + - lbtc_pair.fees.reverse_boltz(invoice_amount_sat)? + - lbtc_pair.fees.reverse_lockup()? + - CLAIM_ABSOLUTE_FEES + ), + }])) .map_err(|_| SwapError::PersistError)?; Ok(SwapLbtcResponse {