Skip to content

frontend: improve insufficient funds error in lightning wallet#4142

Open
strmci wants to merge 1 commit into
BitBoxSwiss:staging-sparkfrom
strmci:lightning_insufficient_funds
Open

frontend: improve insufficient funds error in lightning wallet#4142
strmci wants to merge 1 commit into
BitBoxSwiss:staging-sparkfrom
strmci:lightning_insufficient_funds

Conversation

@strmci
Copy link
Copy Markdown
Collaborator

@strmci strmci commented May 13, 2026

  • prepare custom-amount invoices while editing the amount
  • show fee, total, and insufficient-funds errors in the edit step
  • validate prepared payments against the available balance
  • map Lightning insufficient-funds SDK errors to an app error code
  • map already-used Lightning invoice SDK errors to an app error code

Before asking for reviews, here is a check list of the most common things you might need to consider:

  • updating the Changelog
  • writing unit tests
  • checking if your changes affect other coins or tokens in unintended ways
  • testing on multiple environments (Qt, Android, ...)
  • having an AI review your changes

@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 13, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR unifies payment error handling and refactors custom Lightning invoice amount flows. The backend adds error normalization via lightningPaymentError that maps Breez SDK insufficient-funds errors to a standardized errLightningInsufficientFunds code, integrates balance checks (checkPaymentBalance) into both prepare and send operations, and updates the handler to include the computed fee in error responses. On the frontend, the send context is refactored to debounce custom amounts, automatically prepare quotes via an effect with request-id guarding, and manage quote/error state in a customPrepareState machine. A new PaymentFeeDetails component extracts fee and total rendering logic. Components are updated to use the new context API, and comprehensive tests verify preparation gating, stale response filtering, error handling, and fee approval flows.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@strmci strmci requested a review from Beerosagos May 13, 2026 07:38
@strmci strmci marked this pull request as ready for review May 13, 2026 07:38
@strmci strmci requested a review from a team as a code owner May 13, 2026 07:38
Copy link
Copy Markdown
Collaborator

@Beerosagos Beerosagos left a comment

Choose a reason for hiding this comment

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

I think we should manually check the total debit against the available balance inside PreparePayment. This way, we don't rely on SDK validation, and we can error earlier.

Please also consider a frontend validation for the case when the invoice has no amount and the user has to input it. 🙏

@strmci strmci force-pushed the lightning_insufficient_funds branch from 85c2485 to 046f5e9 Compare May 13, 2026 11:35
@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 13, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/lightning/handlers.go`:
- Line 117: The AvailableSat field assignment currently calls
balance.Available().BigInt().Uint64() unguarded; change it to first obtain b :=
balance.Available().BigInt(), then if b.Sign() > 0 && b.IsUint64() use
b.Uint64() else set AvailableSat to 0 to avoid negative or non-representable
wraparound; update the assignment site in handlers.go where AvailableSat is set
(referencing balance.Available(), BigInt(), IsUint64()) so clients never receive
wrapped/invalid amounts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 71892e58-08ab-405e-931d-6ca55258993c

📥 Commits

Reviewing files that changed from the base of the PR and between 85c2485 and 046f5e9.

📒 Files selected for processing (9)
  • backend/lightning/handlers.go
  • backend/lightning/payments.go
  • backend/lightning/payments_test.go
  • frontends/web/src/api/lightning.ts
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/lightning/send/components/edit-invoice-step.module.css
  • frontends/web/src/routes/lightning/send/components/edit-invoice-step.tsx
  • frontends/web/src/routes/lightning/send/lightning-send-context.test.ts
  • frontends/web/src/routes/lightning/send/lightning-send-context.tsx

Comment thread backend/lightning/handlers.go Outdated
@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 13, 2026

@Beerosagos,

I added the check to PreparePayment and a frontend check for invoices without an amount, so users will see it while entering the amount. I also kept the SDK error updates.

I also checked the Rabbit review comment, but I’m not sure it’s necessary to add. PTAL thanks 🙏

Copy link
Copy Markdown
Collaborator

@Beerosagos Beerosagos left a comment

Choose a reason for hiding this comment

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

The more I look into this, the more I think we should load the fee asynchronously in the edit-invoice step and skip the confirmation step entirely (for invoices without an amount).

We could call the preparePayment endpoint while the user types in the amount and load the fee in the same view. This avoids the need to check for balance errors in the frontend, keep the context cleaner and so on.

I asked codex to recap the suggested changes:

Suggest moving validation to preparePayment() instead of extending the balance API or duplicating balance checks in frontend/backend helpers. For variable-amount Lightning invoices, trigger preparePayment() once the entered amount is
  valid, ideally debounced while typing or on blur. Use that result as the authoritative source for both fee display and insufficient-funds detection, since it already reflects the real quote and failure mode.

  Recommend removing the availableSat addition, the extra backend checkPaymentBalance() after prepare, and the frontend amount > balance heuristic. Those add API surface and duplicate logic, but still do not model the real constraint
  (amount + fee). The current string-based insufficient-funds fallback should stay only if the SDK gives no typed alternative, and it should be treated as a narrow temporary shim.

  For UX, suggest storing the current amount plus the latest prepare state in the send form. Show fee and total immediately when prepare succeeds, and show the returned lightningInsufficientFunds error inline when it fails. That would let
  the user accept the quote directly and potentially skip the separate confirm step for custom-amount invoices. If implemented, make sure prepares are debounced and stale responses cannot overwrite newer input.

WDYT?

@strmci strmci force-pushed the lightning_insufficient_funds branch from 046f5e9 to af0b237 Compare May 18, 2026 09:58
@strmci strmci changed the title backend: improve insufficient funds error in lightning wallet frontend: improve insufficient funds error in lightning wallet May 18, 2026
@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 18, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontends/web/src/api/lightning.ts`:
- Around line 4-6: Change the relative imports in this module to use the project
alias `@/` instead of `./`; replace "./account" with "`@/api/account`" for
AccountCode, TAmountWithConversions, TBalance, TTransactionStatus and replace
"./subscribe" with "`@/api/subscribe`" for TSubscriptionCallback, TUnsubscribe and
subscribeEndpoint so the module follows the frontend import convention.

In `@frontends/web/src/routes/lightning/send/components/invoice-details.tsx`:
- Around line 75-78: Rename the props type TPaymentFeeDetailsProps to TProps in
this component: change the type declaration from TPaymentFeeDetailsProps to
TProps and update all references (the component's props annotation and any other
uses) accordingly within invoice-details.tsx so the component signature (e.g.,
the React function/FC and its parameter typing) uses TProps to comply with the
frontend naming convention.

In `@frontends/web/src/routes/lightning/send/lightning-send-context.test.ts`:
- Line 3: Replace the deep relative import "../../../../__mocks__/i18n" with the
frontend path alias import "`@/__mocks__/i18n`" in the test file so the mock
import uses the project alias instead of leaving the src/routes tree; update the
import statement in lightning-send-context.test.ts accordingly.
- Around line 64-66: The inline props type for the wrapper component should be
replaced with a named alias TProps and used in the wrapper signature; declare
type TProps = { children: ReactNode } and update the wrapper definition to use
TProps (keeping the createElement(LightningSendProvider, null, children) body)
so the props type follows the "TProps" naming guideline and still references
LightningSendProvider and ReactNode.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9355c143-bf28-4ced-bcde-ae6649251721

📥 Commits

Reviewing files that changed from the base of the PR and between 046f5e9 and af0b237.

📒 Files selected for processing (10)
  • backend/lightning/handlers.go
  • backend/lightning/payments.go
  • backend/lightning/payments_test.go
  • frontends/web/src/api/lightning.ts
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/lightning/send/components/confirm-step.tsx
  • frontends/web/src/routes/lightning/send/components/edit-invoice-step.tsx
  • frontends/web/src/routes/lightning/send/components/invoice-details.tsx
  • frontends/web/src/routes/lightning/send/lightning-send-context.test.ts
  • frontends/web/src/routes/lightning/send/lightning-send-context.tsx
💤 Files with no reviewable changes (1)
  • frontends/web/src/routes/lightning/send/components/confirm-step.tsx

Comment thread frontends/web/src/api/lightning.ts Outdated
Comment thread frontends/web/src/routes/lightning/send/components/invoice-details.tsx Outdated
Comment thread frontends/web/src/routes/lightning/send/lightning-send-context.test.ts Outdated
@strmci strmci force-pushed the lightning_insufficient_funds branch 2 times, most recently from 850014f to 130a17b Compare May 18, 2026 11:23
@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 18, 2026

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/lightning/handlers.go`:
- Around line 152-154: The current conditional in the handler uses
jsonBody.AmountSat != nil which prevents returning the structured
insufficient-funds response with fee for fixed-amount invoices; update the
conditional in the block that checks errLightningInsufficientFunds to remove the
AmountSat != nil check so that when fee != nil and errp.Cause(err) ==
errLightningInsufficientFunds you return responseDto{Success: false, ErrorCode:
string(errLightningInsufficientFunds), Data: fee}; if this behavior was
intentionally limited to custom-amount flows instead, add a concise comment
above the check explaining that design decision rather than silently leaving the
guard in place (refer to jsonBody.AmountSat, errLightningInsufficientFunds,
responseDto and errorResponse).

In `@frontends/web/src/routes/lightning/send/components/invoice-details.tsx`:
- Around line 83-95: The total can stay as a skeleton when fiat conversion fails
because convertedTotalDebitAmount is undefined but totalWithFiat remains true;
change the logic in invoice-details.tsx so totalDebitAmount falls back to
satsAmount(quote?.totalDebitSat) when convertedTotalDebitAmount is undefined and
only enable fiat rendering when conversion data exists — i.e., compute
totalDebitAmount = convertedTotalDebitAmount ?? satsAmount(quote?.totalDebitSat)
and pass showFiat={totalWithFiat && Boolean(convertedTotalDebitAmount)} to
AmountValue (functions/variables: useInvoiceAmount, convertedTotalDebitAmount,
totalWithFiat, quote?.totalDebitSat, satsAmount, AmountValue).

In `@frontends/web/src/routes/lightning/send/lightning-send-context.tsx`:
- Around line 122-123: The current error branch unsafely casts TSdkError.data to
TPreparePaymentResponse and stores it in customPrepareState.quote; add a runtime
type guard that validates TSdkError.data has the expected
TPreparePaymentResponse shape (e.g., required fields used later like fee,
amountSat, or paymentRequest) before assigning it to quote, otherwise set quote
to undefined. Update the block around the quote assignment (the quote variable
and the setCustomPrepareState call) to perform this check so only validated
quote objects are stored and downstream fee rendering is safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9fb9f0f1-ff1f-41c1-8d53-3dbc4c6a3dc5

📥 Commits

Reviewing files that changed from the base of the PR and between af0b237 and 130a17b.

📒 Files selected for processing (11)
  • backend/lightning/handlers.go
  • backend/lightning/payments.go
  • backend/lightning/payments_test.go
  • frontends/web/src/api/lightning.ts
  • frontends/web/src/locales/en/app.json
  • frontends/web/src/routes/lightning/send/components/confirm-step.tsx
  • frontends/web/src/routes/lightning/send/components/edit-invoice-step.tsx
  • frontends/web/src/routes/lightning/send/components/invoice-details.tsx
  • frontends/web/src/routes/lightning/send/lightning-send-context.test.ts
  • frontends/web/src/routes/lightning/send/lightning-send-context.tsx
  • frontends/web/src/routes/lightning/send/send.module.css
💤 Files with no reviewable changes (1)
  • frontends/web/src/routes/lightning/send/components/confirm-step.tsx

Comment thread backend/lightning/handlers.go
Comment thread frontends/web/src/routes/lightning/send/lightning-send-context.tsx Outdated
- prepare custom-amount invoices while editing the amount
- show fee, total, and insufficient-funds errors in the edit step
- validate prepared payments against the available balance
- map Lightning insufficient-funds SDK errors to an app error
code
- map already-used Lightning invoice SDK errors to an app
error code
@strmci strmci force-pushed the lightning_insufficient_funds branch from 130a17b to b377434 Compare May 18, 2026 12:25
@strmci
Copy link
Copy Markdown
Collaborator Author

strmci commented May 18, 2026

The more I look into this, the more I think we should load the fee asynchronously in the edit-invoice step and skip the confirmation step entirely (for invoices without an amount).

@Beerosagos yes, makes sense.
I prepared the update, now the amount + fee is compared to the total balance in the edit invoice step. PTAL
Also added another error message for already used invoices.

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.

2 participants