Skip to content

fix(send): surface real BTC fee errors and validate LNURL receive limits - #680

Merged
islandbitcoin merged 4 commits into
mainfrom
eng-btc-fee-error-handling
Aug 7, 2026
Merged

fix(send): surface real BTC fee errors and validate LNURL receive limits#680
islandbitcoin merged 4 commits into
mainfrom
eng-btc-fee-error-handling

Conversation

@islandbitcoin

Copy link
Copy Markdown
Contributor

Summary

Sending from the Breez Spark BTC wallet to a Flash address (or any LNURL destination) failed with a misleading "make sure you have enough balance" message whenever fee estimation failed for any reason. The most common real cause is the receiver's advertised LUD-06 maxSendable cap (ENG-540: IBEX advertises 150k sats instead of 150M), which LNURL-compliant clients reject client-side before ever requesting an invoice.

  • fetchBreezFee returns a typed BreezFeeError (amount-above-max / amount-below-min / insufficient-funds / network / sdk) instead of swallowing every failure into one hardcoded balance string; real errors are recorded to Crashlytics
  • amounts are validated against the receiver's minSendable/maxSendable before prepareLnurlPay, so the UI shows the actual limit (e.g. "The most this recipient can receive per payment is $97.03 (150,000 sats)")
  • the send-details screen resolves the receiver's limits once per destination and DetailAmountNote validates as the user types for BTC-wallet sends (previously only USD/USDT lnurl sends were validated)
  • ConfirmationWalletFee: fixed the dead fee === "null" string comparison and wired typed-error mapping
  • useSwap: BTC→USD swap fee errors no longer all report as "amount exceeds balance"
  • 5 new i18n keys in en + all 23 locales (English placeholder convention per feat(mobile): Plaid Link SDK cutover for Bridge external accounts [ENG-524] #668/feat(bank): fall back to manual entry when Plaid Link is blocked #678)

Linear: ENG-540

Test plan

  • yarn tsc:check clean
  • yarn test — 50 suites / 267 tests pass, incl. 2 new suites covering msat→sat limit conversion (with the exact 150k-cap regression case), bounds validation, SDK error classification, and message mapping
  • node utils/check-translation-drift.js green; yarn update-translations regenerated and stable
  • Manual: BTC-wallet send >150k sats to a Flash address shows the receiver-limit message inline; retest after IBEX raises maxSendable

🤖 Generated with Claude Code

https://claude.ai/code/session_01G7A41jET8aH7u5WXP7EZoS

Sending from the Breez Spark BTC wallet to a Flash address (or any LNURL
destination) failed with a misleading 'make sure you have enough balance'
message whenever anything went wrong in fee estimation. The most common
real cause is the receiver's advertised LUD-06 maxSendable cap (ENG-540:
IBEX advertises 150k sats instead of 150M), which the SDK rejects
client-side before requesting an invoice.

- fetchBreezFee now returns a typed BreezFeeError instead of swallowing
  every failure into one hardcoded balance string; real errors are
  recorded to Crashlytics
- amounts are validated against the receiver's minSendable/maxSendable
  before prepareLnurlPay, so the UI can show the actual limit
- send-details screen resolves the receiver's limits per destination and
  DetailAmountNote validates as the user types for BTC-wallet sends
  (previously only USD/USDT lnurl sends were validated)
- ConfirmationWalletFee: fix dead 'fee === "null"' string comparison,
  map typed errors to accurate messages
- useSwap: stop reporting every fee error as 'amount exceeds balance'
- new i18n keys in en + all 23 locales (English placeholder convention)
- unit tests for limit conversion/validation, error classification, and
  message mapping

Linear: ENG-540

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7A41jET8aH7u5WXP7EZoS
- extract shared useFormatSats hook, replacing four hand-rolled copies of
  the sats formatting closure (details screen, DetailAmountNote,
  ConfirmationWalletFee, useSwap)
- resolve the receiver's LNURL payRequest once on the details screen and
  pass it through to fetchBreezFee, removing the duplicate network
  round-trip to the receiver's LNURL service on every BTC send
  (fetchLnurlLimits -> fetchLnurlPayRequest)
- add component tests for DetailAmountNote's BTC receiver-limit
  validation branch (over-max regression case, below-min, within-bounds,
  unknown limits, lnurl payment type)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7A41jET8aH7u5WXP7EZoS
@linear

linear Bot commented Aug 6, 2026

Copy link
Copy Markdown

ENG-540

Dread and others added 2 commits August 6, 2026 17:06
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7A41jET8aH7u5WXP7EZoS
The added knownPayRequest parameter pushed the signature to five positional
params, tripping max-params on the changed-lines lint gate. An options
object is the better API anyway — no optional-middle-arg call sites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7A41jET8aH7u5WXP7EZoS
@islandbitcoin
islandbitcoin merged commit 47b8c69 into main Aug 7, 2026
10 checks passed
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.

1 participant