Skip to content

fix: add quickpay daily spend limit - #672

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

fix: add quickpay daily spend limit#672
ovitrif wants to merge 9 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 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 sats before pay, kept on Success/Pending, and released if a pending payment later fails
  • 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
  • Daily-limit errors and slider labels are localized
  • Successful QuickPay shows amount plus the paid routing fee

Companion Android PR: synonymdev/bitkit-android#1159

Linked Issues/Tasks

Screenshot / Video

Happy flow — under the daily cap Over the 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.

Automated Checks

  • Unit tests added: day-keyed sat 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 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

This PR adds a configurable QuickPay daily spend cap, persists and backs up its multiplier, and tracks reserved spend around payment execution.

  • Adds daily-cap routing and thread-safe day-keyed spend accounting.
  • Adds QuickPay settings UI, localization, backup support, and focused tests.
  • Includes routing fees in the successful-payment amount display.

Confidence Score: 4/5

The timeout-to-terminal-failure lifecycle must release its retained QuickPay reservation before this PR is safe to merge.

A payment that times out keeps its reservation as intended while pending, but a later terminal failure never releases it, so retries and subsequent payments are evaluated against spend that never occurred.

Files Needing Attention: Bitkit/Views/Wallets/Send/SendQuickpay.swift and the pending-payment failure transition

Important Files Changed

Filename Overview
Bitkit/Views/Wallets/Send/SendQuickpay.swift Adds atomic spend reservation and fee-inclusive success display, but does not release retained spend when a timed-out payment later fails.
Bitkit/Utilities/QuickPaySpendStore.swift Adds locked, day-keyed aggregate reservation storage with reserve and release operations.
Bitkit/Utilities/PaymentNavigationHelper.swift Extends QuickPay eligibility with fixed-payment extraction and daily-cap checks.
Bitkit/Utilities/QuickPayLimits.swift Centralizes thresholds, multiplier validation, currency conversion, daily-cap calculation, and fee-inclusive amount arithmetic.
Bitkit/ViewModels/WalletViewModel.swift Returns the settled payment hash and routing fee from Lightning sends.
Bitkit/ViewModels/SettingsViewModel.swift Persists, resets, restores, sanitizes, and backs up the daily multiplier.
Bitkit/Views/Settings/Quickpay/QuickpaySettings.swift Adds the daily-limit explanation and multiplier slider to QuickPay settings.

Sequence Diagram

sequenceDiagram
    participant User
    participant Nav as PaymentNavigationHelper
    participant QuickPay as SendQuickpay
    participant Store as QuickPaySpendStore
    participant Wallet as WalletViewModel
    participant Pending as Pending/Failure flow

    User->>Nav: Scan eligible fixed invoice
    Nav->>Store: Read today's spend
    Nav-->>QuickPay: Route to QuickPay
    QuickPay->>Store: Reserve invoice amount
    QuickPay->>Wallet: Send with timeout
    Wallet-->>QuickPay: Timeout
    QuickPay-->>Pending: Keep reservation and show pending
    Wallet-->>Pending: Terminal failure
    Pending-->>User: Show failure
    User->>QuickPay: Retry
    QuickPay->>Store: Reserve same amount again
Loading

Reviews (1): Last reviewed commit: "fix: port Android QuickPay follow-ups" | Re-trigger Greptile

Comment thread Bitkit/Views/Wallets/Send/SendQuickpay.swift

@ben-kaufman ben-kaufman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two findings below.

Comment thread Bitkit/Views/Wallets/Send/SendQuickpay.swift
Comment thread Bitkit/Views/Wallets/Send/SendQuickpay.swift
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

2 participants