Skip to content

feat: add boltz savings swap#1081

Open
coreyphillips wants to merge 6 commits into
masterfrom
feat/savings-swap
Open

feat: add boltz savings swap#1081
coreyphillips wants to merge 6 commits into
masterfrom
feat/savings-swap

Conversation

@coreyphillips

@coreyphillips coreyphillips commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

This PR adds a swap-based path for transferring spending balance to savings, so Lightning funds can move on-chain through a Boltz reverse swap instead of only by closing a channel.

Description

  • Adds a Boltz reverse swap flow to the transfer-to-savings journey. The confirm screen now shows a live quote (amount to savings, network fee, service fee, and the amount you will receive) and lets the user proceed with a swap or fall back to closing the channel.
  • Guards against amounts that are too low to swap, holding back a small reserve for Lightning routing fees and surfacing a clear message when the amount cannot be transferred.
  • Waits for the on-chain claim during the progress step and resumes any pending swaps when the wallet starts, refreshing balances automatically once a swap lands on-chain. The updates stream now also stops with the node when the app goes to background.
  • Adds a Swaps section under Dev Settings to list swaps and claim a reverse swap, backed by a new service that wraps the Boltz module. The manual claim button only shows while the swap is actually claimable (lockup on-chain and no claim broadcast yet).
  • Adds a reusable slider component used by the swap amount controls.
  • Bumps bitkit-core to 0.5.1, which introduces the Boltz module this flow depends on.

Preview

QA Notes

Manual Tests

  • 1. With a spending balance, Transfer to Savings → Savings Confirm: quote shows amount to savings, network fee, service fee, and you'll receive.
  • 2. Savings Confirm → change amount: quote recomputes for the new amount.
  • 3. Savings Confirm → set an amount below the swap minimum: amount-too-low message shows and confirm is blocked.
  • 4a. Savings Confirm → confirm swap → Savings Progress: completes after the on-chain claim.
    • 4b. After claim: savings balance reflects the swapped funds without a manual sync.
  • 5. regression: Savings Confirm → Close channel instead: falls back to the channel-close path.
  • 6. regression: Start the app with a pending swap: swap resumes and balance updates once it lands on-chain.
  • 7a. Dev Settings → Swaps → tap a swap → Swap Detail: Claim now shows only for an unclaimed reverse swap with its lockup in mempool or confirmed.
    • 7b. Swap Detail of a created, expired, refunded, or claimed swap: no Claim button.

Automated Checks

  • Unit tests added: savings swap quote limits, slider clamping, swap execution outcomes (claimed, error, timeout, payment failure), and that a second start is ignored while a swap is in flight, in TransferViewModelTest.kt.
  • Unit tests added: claimable status gating, swap list sorting, and manual claim in SwapsViewModelTest.kt.
  • Unit tests modified: inject the new Boltz service dependency into the wallet view model setup in WalletViewModelTest.kt.
  • Ran locally against bitkit-core 0.5.1: compileDevDebugKotlin, testDevDebugUnitTest, and detekt all pass.

Comment thread app/src/main/java/to/bitkit/services/BoltzService.kt Fixed
@coreyphillips coreyphillips marked this pull request as ready for review July 16, 2026 12:58
@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a Boltz reverse-swap path for moving Lightning funds into savings. The main changes are:

  • Live swap limits, fee quotes, and adjustable transfer amounts.
  • Reverse-swap creation, payment, claim tracking, and startup resumption.
  • Swap history, detail, and manual claim tools in developer settings.
  • A reusable amount slider and a bitkit-core dependency update.

Confidence Score: 4/5

The swap lifecycle can report completion too early and can lose claim handling during startup, navigation, or event-subscription races.

  • Pending swaps are shown as completed transfers.
  • Claim events can arrive before collectors subscribe.
  • Failed background update startup is not retried.
  • Concurrent quote requests can restore stale amounts.

TransferViewModel.kt, SavingsProgressScreen.kt, and WalletViewModel.kt

Important Files Changed

Filename Overview
app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt Adds quote calculation and reverse-swap execution, with races in quote replacement and claim-event subscription.
app/src/main/java/to/bitkit/ui/screens/transfer/SavingsProgressScreen.kt Adds swap progress handling but treats pending swaps as complete and ties execution to the screen lifecycle.
app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt Adds swap resumption and balance refresh handling without retrying failed stream startup.
app/src/main/java/to/bitkit/services/BoltzService.kt Adds the Boltz FFI wrapper and a non-replaying event bridge used by swap execution and wallet updates.
app/src/main/java/to/bitkit/ui/screens/transfer/SavingsConfirmScreen.kt Adds live quotes, amount adjustment, swap confirmation, and the channel-close fallback.
app/src/main/java/to/bitkit/viewmodels/SwapsViewModel.kt Adds sorted swap history, manual claims, and status-based claim gating.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Savings Progress
    participant TVM as TransferViewModel
    participant LN as LightningRepo
    participant Boltz as BoltzService
    participant WVM as WalletViewModel
    UI->>TVM: executeSavingsSwap()
    TVM->>Boltz: createReverseSwap()
    TVM-->>Boltz: schedule event collection
    TVM->>LN: pay hold invoice
    Boltz-->>TVM: Claimed or Error
    alt Event observed
        TVM-->>UI: Success or Failure
    else No event within 60 seconds
        TVM-->>UI: Pending
        UI-->>UI: Show success
        WVM->>Boltz: Continue background updates
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Savings Progress
    participant TVM as TransferViewModel
    participant LN as LightningRepo
    participant Boltz as BoltzService
    participant WVM as WalletViewModel
    UI->>TVM: executeSavingsSwap()
    TVM->>Boltz: createReverseSwap()
    TVM-->>Boltz: schedule event collection
    TVM->>LN: pay hold invoice
    Boltz-->>TVM: Claimed or Error
    alt Event observed
        TVM-->>UI: Success or Failure
    else No event within 60 seconds
        TVM-->>UI: Pending
        UI-->>UI: Show success
        WVM->>Boltz: Continue background updates
    end
Loading

Reviews (1): Last reviewed commit: "fix: gate swap claim and harden boltz fl..." | Re-trigger Greptile

Comment thread app/src/main/java/to/bitkit/ui/screens/transfer/SavingsProgressScreen.kt Outdated
Comment thread app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt Outdated
Comment thread app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt Outdated
Comment thread app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt
Comment thread app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants