Skip to content

Commit

Permalink
feat: added onchain_amount_sat field
Browse files Browse the repository at this point in the history
  • Loading branch information
yse committed Mar 21, 2024
1 parent 3516716 commit b6e1d84
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 39 deletions.
22 changes: 17 additions & 5 deletions cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64>,

#[arg(short, long)]
invoice_amount_sat: Option<u64>,
},
/// List incoming and outgoing payments
ListPayments,
/// Get the balance of the currently loaded wallet
Expand All @@ -40,8 +46,14 @@ pub(crate) async fn handle_command(
command: Command,
) -> Result<String> {
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: {}",
Expand Down
7 changes: 5 additions & 2 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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: {}",
Expand Down
18 changes: 17 additions & 1 deletion lib/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ impl ToString for SwapStatus {
}
}

pub struct ReceivePaymentRequest {
pub invoice_amount_sat: Option<u64>,
pub onchain_amount_sat: Option<u64>,
}

pub struct SendPaymentResponse {
pub txid: String,
}
Expand Down Expand Up @@ -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<u64>,
// pub onchain_amount_sat: Option<u64>,
}

pub enum PaymentType {
Expand Down
3 changes: 2 additions & 1 deletion lib/src/persist/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;",
]
}
19 changes: 11 additions & 8 deletions lib/src/persist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(
Expand All @@ -45,9 +45,10 @@ impl Persister {
preimage,
redeem_script,
blinding_key,
invoice_amount_sat
invoice_amount_sat,
onchain_amount_sat
)
VALUES (?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?)
",
)?;

Expand All @@ -58,6 +59,7 @@ impl Persister {
&swap.redeem_script,
&swap.blinding_key,
&swap.invoice_amount_sat,
&swap.onchain_amount_sat,
))?
}

Expand All @@ -73,26 +75,27 @@ impl Persister {
Ok(())
}

pub fn list_ongoing_swaps(&self) -> Result<Vec<OngoingSwap>> {
pub fn list_ongoing_swaps(&self) -> Result<Vec<OngoingReceiveSwap>> {
let con = self.get_connection()?;

let mut stmt = con.prepare("SELECT * FROM ongoing_swaps")?;

let swaps: Vec<OngoingSwap> = stmt
let swaps: Vec<OngoingReceiveSwap> = stmt
.query_map(params![], |row| self.sql_row_to_swap(row))?
.map(|i| i.unwrap())
.collect();

Ok(swaps)
}

fn sql_row_to_swap(&self, row: &Row) -> Result<OngoingSwap, rusqlite::Error> {
Ok(OngoingSwap {
fn sql_row_to_swap(&self, row: &Row) -> Result<OngoingReceiveSwap, rusqlite::Error> {
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)?,
})
}
}
65 changes: 43 additions & 22 deletions lib/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<SwapLbtcResponse, SwapError> {
pub fn receive_payment(
&self,
req: ReceivePaymentRequest,
) -> Result<SwapLbtcResponse, SwapError> {
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()?;
Expand All @@ -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()?;
Expand All @@ -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 {
Expand Down

0 comments on commit b6e1d84

Please sign in to comment.