Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
RUST_BACKTRACE: 1
RUST_LOG: orange_sdk=debug,graduated_rebalancer=debug,ldk_node=info,integration_tests=info,test_utils=info

jobs:
rust_tests:
name: Rust Checks
Expand Down Expand Up @@ -40,7 +44,7 @@ jobs:
run: cargo check -p orange-cli

- name: Run tests
run: cargo test --features _test-utils -- --test-threads=2
run: cargo test --features _test-utils -- --test-threads=2 --nocapture

cashu_tests:
name: Cashu Tests
Expand All @@ -59,4 +63,4 @@ jobs:
- uses: Swatinem/rust-cache@v2.7.8

- name: Run cashu tests
run: cargo test --features _cashu-tests -- --test-threads=2
run: cargo test --features _cashu-tests -- --test-threads=2 --nocapture
14 changes: 8 additions & 6 deletions graduated-rebalancer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,21 @@ pub trait LightningWallet: Send + Sync {
/// Check if we already have a channel with the LSP
fn has_channel_with_lsp(&self) -> bool;

/// Open a channel with the LSP using on-chain funds
/// Open a channel with the LSP using all available on-chain funds
/// (minus fees and anchor reserves).
fn open_channel_with_lsp(
&self, amt: Amount,
&self,
) -> Pin<Box<dyn Future<Output = Result<u128, Self::Error>> + Send + '_>>;

/// Wait for a channel pending notification, returns the new channel's outpoint
fn await_channel_pending(
&self, channel_id: u128,
) -> Pin<Box<dyn Future<Output = OutPoint> + Send + '_>>;

/// Splice funds from on-chain to an existing channel with the LSP
/// Splice all available on-chain funds (minus fees and anchor reserves) into
/// an existing channel with the LSP.
fn splice_to_lsp_channel(
&self, amt: Amount,
&self,
) -> Pin<Box<dyn Future<Output = Result<u128, Self::Error>> + Send + '_>>;

/// Wait for a splice pending notification, returns the splice outpoint
Expand Down Expand Up @@ -344,7 +346,7 @@ where
let (channel_outpoint, user_channel_id) = if self.ln_wallet.has_channel_with_lsp() {
log_info!(self.logger, "Splicing into channel with LSP with on-chain funds");

let user_chan_id = match self.ln_wallet.splice_to_lsp_channel(params.amount).await {
let user_chan_id = match self.ln_wallet.splice_to_lsp_channel().await {
Ok(chan_id) => chan_id,
Err(e) => {
log_error!(self.logger, "Failed to open channel with LSP: {e:?}");
Expand All @@ -362,7 +364,7 @@ where
} else {
log_info!(self.logger, "Opening channel with LSP with on-chain funds");

let user_chan_id = match self.ln_wallet.open_channel_with_lsp(params.amount).await {
let user_chan_id = match self.ln_wallet.open_channel_with_lsp().await {
Ok(chan_id) => chan_id,
Err(e) => {
log_error!(self.logger, "Failed to open channel with LSP: {e:?}");
Expand Down
51 changes: 9 additions & 42 deletions orange-sdk/src/lightning_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,20 +400,16 @@ impl LightningWallet {
}
}

pub(crate) async fn splice_balance_into_channel(
&self, amount: Amount,
) -> Result<UserChannelId, NodeError> {
pub(crate) async fn splice_all_into_channel(&self) -> Result<UserChannelId, NodeError> {
// find existing channel to splice into
let channels = self.inner.ldk_node.list_channels();
let channel = channels.iter().find(|c| c.counterparty_node_id == self.inner.lsp_node_id);

match channel {
Some(chan) => {
self.inner.ldk_node.splice_in(
&chan.user_channel_id,
chan.counterparty_node_id,
amount.sats_rounding_up(),
)?;
self.inner
.ldk_node
.splice_in_with_all(&chan.user_channel_id, chan.counterparty_node_id)?;
Ok(chan.user_channel_id)
},
None => {
Expand All @@ -424,23 +420,9 @@ impl LightningWallet {
}

pub(crate) async fn open_channel_with_lsp(&self) -> Result<UserChannelId, NodeError> {
let bal = self.inner.ldk_node.list_balances().spendable_onchain_balance_sats;

// need a dummy p2wsh address to estimate the fee, p2wsh is used for LN channels
// let fake_addr = Address::p2wsh(Script::new(), self.inner.ldk_node.config().network);
//
// let fee = self
// .inner
// .ldk_node
// .onchain_payment()
// .estimate_send_all_to_address(&fake_addr, true, None)?;
// todo get real fee
let fee = 1000;

let id = self.inner.ldk_node.open_channel(
let id = self.inner.ldk_node.open_channel_with_all(
self.inner.lsp_node_id,
self.inner.lsp_socket_addr.clone(),
bal - fee,
None,
None,
)?;
Expand Down Expand Up @@ -541,12 +523,9 @@ impl graduated_rebalancer::LightningWallet for LightningWallet {
}

fn open_channel_with_lsp(
&self, _amt: Amount,
&self,
) -> Pin<Box<dyn Future<Output = Result<u128, Self::Error>> + Send + '_>> {
Box::pin(async move {
// we don't use the amount and just use our full spendable balance in open_channel_with_lsp
self.open_channel_with_lsp().await.map(|c| c.0)
})
Box::pin(async move { self.open_channel_with_lsp().await.map(|c| c.0) })
}

fn await_channel_pending(
Expand All @@ -570,21 +549,9 @@ impl graduated_rebalancer::LightningWallet for LightningWallet {
}

fn splice_to_lsp_channel(
&self, amt: Amount,
&self,
) -> Pin<Box<dyn Future<Output = Result<u128, Self::Error>> + Send + '_>> {
let bal = self.inner.ldk_node.list_balances();
// if we don't have enough onchain balance, return error
// if we are within 1,000 sats of the amount, reduce the amount to account for fees
if bal.spendable_onchain_balance_sats < amt.sats_rounding_up() {
return Box::pin(async move { Err(NodeError::InsufficientFunds) });
} else if bal.spendable_onchain_balance_sats < amt.sats_rounding_up() + 1_000 {
let reduced_amt = amt.saturating_sub(Amount::from_sats(1_000).expect("valid amount"));
return Box::pin(async move {
self.splice_balance_into_channel(reduced_amt).await.map(|c| c.0)
});
}

Box::pin(async move { self.splice_balance_into_channel(amt).await.map(|c| c.0) })
Box::pin(async move { self.splice_all_into_channel().await.map(|c| c.0) })
}

fn await_splice_pending(
Expand Down
17 changes: 12 additions & 5 deletions orange-sdk/src/trusted_wallet/dummy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ impl DummyTrustedWallet {
.await
.unwrap();
}

let _ = payment_success_sender.send(());
},
Event::PaymentReceived { payment_id, amount_msat, payment_hash, .. } => {
// convert id
Expand Down Expand Up @@ -258,10 +260,8 @@ impl DummyTrustedWallet {
DummyTrustedWallet { current_bal_msats, payments, ldk_node, payment_success_flag }
}

pub(crate) async fn await_payment_success(&self) {
let mut flag = self.payment_success_flag.clone();
flag.mark_unchanged();
let _ = flag.changed().await;
fn payment_wait_timeout() -> Duration {
if std::env::var("CI").is_ok() { Duration::from_secs(120) } else { Duration::from_secs(20) }
}
}

Expand Down Expand Up @@ -384,6 +384,8 @@ impl TrustedWalletInterface for DummyTrustedWallet {
) -> Pin<Box<dyn Future<Output = Option<ReceivedLightningPayment>> + Send + '_>> {
Box::pin(async move {
let id = channelmanager::PaymentId(payment_hash);
let mut flag = self.payment_success_flag.clone();
flag.mark_unchanged();
loop {
if let Some(payment) = self.ldk_node.payment(&id) {
let counterparty_skimmed_fee_msat = match payment.kind {
Expand All @@ -408,7 +410,12 @@ impl TrustedWalletInterface for DummyTrustedWallet {
PaymentStatus::Failed => return None,
}
}
self.await_payment_success().await;
if !matches!(
tokio::time::timeout(Self::payment_wait_timeout(), flag.changed()).await,
Ok(Ok(()))
) {
return None;
}
}
})
}
Expand Down
Loading
Loading