Skip to content

feat: add quickpay daily spend limit - #672

Open
ovitrif wants to merge 51 commits into
masterfrom
fix/670-quickpay-day-limit
Open

feat: add quickpay daily spend limit#672
ovitrif wants to merge 51 commits into
masterfrom
fix/670-quickpay-day-limit

Conversation

@ovitrif

@ovitrif ovitrif commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Closes #670

This PR ports QuickPay daily spend limits from Android (synonymdev/bitkit-android#1159) so auto-pay stays PIN-free under a configurable daily cap.

Description

QuickPay stays confirmation-free and PIN-free while a payment is under the per-tx threshold and the daily cap (threshold × multiplier USD). Once the cap would be exceeded, the payment opens Confirm, where PIN for payments still applies if that setting is on.

  • Daily multiplier steps: 1, 3, 5, 10, 50 (default 5)
  • Spend is reserved in USD cents before pay, kept on Success/Pending, and released on failure only from the matching calendar day
  • Spend resets on the local calendar day and is kept if the clock rolls back
  • Settings add a second slider and show the resolved daily $ cap
  • The multiplier is included in settings backup as quickPayDailyLimitMultiplier
  • Slider labels and the currency-conversion error are localized. Over-cap is silent Confirm
  • Successful QuickPay shows amount plus the paid routing fee
  • Over-cap or a lost reserve race replaces QuickPay with Confirm, so Back does not return to the auto-pay loader
  • Try Again remounts QuickPay so a new payment starts

Out of scope

  • Clock or timezone jumps: rollback keeps spend; only a later local date opens a new bucket
  • In-flight spend after process death past midnight: at most one under-count on the new day, no over-count
  • Scanning an invoice that already paid: success shows the invoice amount, without the routing fee. The daily cap still counted it

Preview

Updated screenshot, integrating designer's feedback.

Screenshot
QuickPay Settings Over Cap → Confirm + PIN
happy-daily-cap.mp4
over-cap.mp4

QA Notes

Manual Tests

  • 1. Settings → QuickPay → enable QuickPay → move threshold and daily multiplier sliders: resolved daily $ copy updates (threshold × multiplier).
  • 2. Unlocked, under per-tx and daily cap, PIN for payments on → scan a fixed-amount LN invoice: QuickPay runs with no payment PIN.
  • 3. Exhaust or exceed the daily cap → scan another eligible invoice: Confirm opens; payment PIN is required if that setting is on.
  • 4. regression: Settings → QuickPay → leave QuickPay off → scan a fixed-amount LN invoice: Confirm still opens.
  • 5. regression: Variable amount LN invoice / LNURL-pay: still lands on Amount, not QuickPay.
  • 6. QuickPay success: displayed amount includes the paid routing fee.
  • 7. Over daily cap → Confirm: Back does not return to the QuickPay loader.
  • 8. QuickPay failure → Try Again: a new payment starts.

Automated Checks

  • Unit tests added: day-keyed USD-cent spend reserve/release/reset and clock-rollback keep-spend in BitkitTests/QuickPaySpendStoreTests.swift.
  • Unit tests added: QuickPay routing under the cap, at the cap, and over the cap, plus replace-QuickPay navigation, in BitkitTests/PaymentNavigationHelperTests.swift.
  • Unit tests added: fee-inclusive success amount and multiplier fallback in BitkitTests/QuickPayLimitsTests.swift.
  • Unit tests modified: backup/restore of the daily multiplier, including the Android key, in BitkitTests/AddressTypeSettingsTests.swift.
  • node scripts/validate-translations.js: 0 errors.
  • Focused unit tests passed locally on iPhone 16 (iOS 18.5).
  • CI: standard build and test checks run by the PR bot.

Track USD spend on the local calendar day so QuickPay can enforce a daily cap.
Expose the Android daily multiplier steps and resolved dollar cap in settings, and keep the value in backup.
Keep auto-pay PIN-free under the daily limit, record spend on success or pending, and send over-cap payments to Confirm.
@ovitrif ovitrif changed the title fix: add QuickPay daily spend limit fix: add quickpay daily spend limit Aug 18, 2026
@ovitrif ovitrif self-assigned this Aug 18, 2026
@ovitrif ovitrif added this to the 2.5.0 milestone Aug 18, 2026
@ovitrif
ovitrif marked this pull request as ready for review August 18, 2026 16:30
@ovitrif
ovitrif requested review from ben-kaufman and pwltr August 18, 2026 16:30
@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown

Greptile Summary

The PR adds a persisted, configurable daily USD limit for PIN-free QuickPay and coordinates reservations across dispatch, pending settlement, terminal events, retries, backup, and restoration.

  • Adds daily-cap calculation, atomic spend reservation, day rollover, and LDK reconciliation.
  • Centralizes QuickPay dispatch and terminal-event coordination.
  • Adds the multiplier setting, localized UI, backup support, fee-inclusive success amounts, and focused tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
Bitkit/Utilities/QuickPayPaymentCoordinator.swift Centralizes QuickPay reservation, dispatch, recovery, terminal-event attribution, fee application, and result navigation.
Bitkit/Utilities/QuickPaySpendStore.swift Implements synchronized, persisted daily spend accounting with hash-bound reservations and LDK reconciliation.
Bitkit/ViewModels/AppViewModel.swift Routes Lightning terminal events through the QuickPay coordinator before resolving pending send-sheet state.
Bitkit/ViewModels/WalletViewModel.swift Integrates payment event handling and reconciliation with the revised QuickPay lifecycle.
Bitkit/Utilities/PaymentNavigationHelper.swift Applies the per-payment and daily limits when selecting QuickPay and replaces over-cap QuickPay routes with confirmation.
Bitkit/Models/BackupPayloads.swift Adds backward-compatible optional persistence for the QuickPay ledger.
Bitkit/Models/SettingsBackupConfig.swift Adds cross-platform backup mappings for the QuickPay daily multiplier and ledger.
Bitkit/Views/Settings/Quickpay/QuickpaySettings.swift Adds multiplier controls and displays the resolved daily QuickPay cap.
BitkitTests/QuickPayPaymentCoordinatorTests.swift Covers immediate terminal events, ambiguous dispatch, recovery, reconciliation, and overlapping in-flight operations.
BitkitTests/QuickPaySpendStoreTests.swift Covers reservation, release, daily rollover, persistence, and clock-rollback behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Fixed-amount Lightning request] --> B{QuickPay enabled and per-payment threshold met?}
    B -->|No| C[Confirmation and optional PIN]
    B -->|Yes| D{Daily spend reservation succeeds?}
    D -->|No| C
    D -->|Yes| E[Dispatch Lightning payment]
    E -->|Success| F[Keep daily spend and show fee-inclusive success]
    E -->|Pending| G[Keep reservation and track by payment hash]
    G -->|Later success| F
    G -->|Later failure| H[Release matching-day reservation]
    E -->|Failure| H
    H --> I[Show failure and allow retry]
Loading

Reviews (4): Last reviewed commit: "fix: update QuickPay daily-limit copy an..." | Re-trigger Greptile

Comment thread Bitkit/Views/Wallets/Send/SendQuickpay.swift Outdated
ben-kaufman

This comment was marked as resolved.

@ovitrif
ovitrif requested a review from ben-kaufman August 18, 2026 22:02
ben-kaufman

This comment was marked as resolved.

@ovitrif ovitrif removed this from the 2.5.0 milestone Aug 19, 2026
@ovitrif

This comment was marked as outdated.

@ovitrif
ovitrif marked this pull request as draft August 19, 2026 13:59
@ovitrif
ovitrif marked this pull request as ready for review August 19, 2026 22:21
Comment thread Bitkit/Utilities/QuickPayLimits.swift Outdated
@pwltr

pwltr commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Tested the QuickPay daily limit flow on local regtest with fixed-amount hold invoices.

Covered:

  • QuickPay under the per-payment threshold and daily cap stays PIN-free and moves to Pending after the hold invoice timeout.
  • Settling the hold invoice moves Pending -> Success.
  • Canceling the hold invoice moves Pending -> Failure.
  • Exhausting the daily cap routes the next eligible fixed invoice to Confirm without returning to the QuickPay loader on Back.
  • Failed QuickPay reservations are released, while successful/pending spend remains counted against the daily cap.
  • Try Again from QuickPay failure starts a fresh payment attempt.
  • QuickPay-off and variable-amount invoice routes still go through the expected non-QuickPay screens.

The timeout now starts after lightningService.send returns the payment hash. That seems fine if LDK submission is expected to return quickly, but it’s worth keeping in mind that pre-hash submission time is no longer covered by the pending-screen timeout.

I also reviewed the code structure around QuickPaySpendStore, QuickPayLimits, and the send navigation changes. The implementation is reasonably contained and the focused unit tests cover the important ledger/day-boundary behavior. No blocking issues from my side.

@ovitrif ovitrif changed the title fix: add quickpay daily spend limit feat: add quickpay daily spend limit Aug 24, 2026
Pass feePaidMsat through complete() like Android signalCompletion.
Instant failure after send no longer navigates to Success.
Match Android AppCacheData.quickPayLedger. Still decode the three older
spend fields if a payload has them and no ledger.
@ovitrif
ovitrif removed the request for review from piotr-iohk August 24, 2026 16:35
@ovitrif
ovitrif marked this pull request as ready for review August 24, 2026 16:35
@ovitrif
ovitrif requested a review from piotr-iohk August 24, 2026 16:41
Comment thread BitkitTests/QuickPayPaymentCoordinatorTests.swift Outdated
Comment thread Bitkit/Utilities/QuickPayPaymentCoordinator.swift
Comment thread Bitkit/Utilities/QuickPayPaymentCoordinator.swift
Comment thread Bitkit/Utilities/QuickPayPaymentCoordinator.swift
Comment thread Bitkit/Models/BackupPayloads.swift
Comment thread Bitkit/Utilities/QuickPayPaymentCoordinator.swift
@ovitrif
ovitrif requested a review from ben-kaufman August 25, 2026 08:04
Comment thread Bitkit/Utilities/QuickPayPaymentCoordinator.swift Outdated
@ovitrif
ovitrif requested a review from ben-kaufman August 25, 2026 15:41
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.

Port QuickPay daily spend limit from Android

4 participants