Skip to content

fix(flash): cap IBEX receive invoice expiration at 60s (ENG-427)#410

Merged
islandbitcoin merged 1 commit into
mainfrom
jabariennis/eng-427-fixflash-align-ibex-receive-invoice-ux-with-60s-expiry-limit
Jun 19, 2026
Merged

fix(flash): cap IBEX receive invoice expiration at 60s (ENG-427)#410
islandbitcoin merged 1 commit into
mainfrom
jabariennis/eng-427-fixflash-align-ibex-receive-invoice-ux-with-60s-expiry-limit

Conversation

@islandbitcoin

Copy link
Copy Markdown
Contributor

Summary

Flash uses non-msat IBEX currency accounts (USD/USDT/JMD) for its receive flows. IBEX caps BOLT11 receive-invoice expiry by account type — 60s for these accounts, 900s only for msat accounts. The backend defaulted to 5 minutes (300s) and sent expiration: 300 to IBEX, which silently capped it to 60s. So the requested value was never honored, and the mobile receive screen shows a 60s countdown that looked like a bug.

This aligns the backend with the real IBEX limit so we never request an expiration IBEX will ignore.

Changes

  • invoice-expiration.ts — add a documented IBEX_RECEIVE_MAX_EXPIRATION_SECONDS (60s) constant recording the IBEX account-type limit, an ibexReceiveDefaultExpirationMinutes default, and a pure cappedIbexReceiveExpiration() clamp.
  • ibex/client.ts — clamp expiration centrally in the addInvoice wrapper (the single choke point for every IBEX receive invoice), so no caller can request more than 60s, regardless of an explicit expiresIn override.
  • add-invoice-for-wallet.ts — default the USD receive flows to 60s instead of 300s.
  • Tests — extend invoice-expiration.spec.ts with the policy, including a regression guard that a 5-minute (300s) request can never reach IBEX.

Notes / decisions

  • Mobile needs no change — the receive countdown already decodes the actual BOLT11 expiry (prToDateString / decodeInvoiceString(...).timeExpireDateString), so it will correctly show 60s.
  • The clamp scopes naturally to IBEX: it lives in Ibex.addInvoice, so the legacy no-amount / LND WalletInvoiceBuilder path is untouched.
  • undefined expiration is passed through so IBEX applies its own account default.

Acceptance criteria

  • Backend expiration defaults for current Flash IBEX receive flows cap at 60s
  • Tests cover the policy so a 5-minute default can't be reapplied to non-msat accounts
  • Mobile receive countdown remains based on the actual BOLT11 expiry (unchanged)
  • The IBEX account-type limit is documented next to the expiry policy

Closes ENG-427.

🤖 Generated with Claude Code

Flash uses non-msat IBEX currency accounts (USD/USDT/JMD) for its receive
flows, which IBEX limits to a 60s BOLT11 expiry; only msat accounts allow
up to 900s. The backend defaulted to 5 minutes (300s) and IBEX silently
capped that down to 60s, so the requested value was never honored.

- Add a documented IBEX_RECEIVE_MAX_EXPIRATION_SECONDS (60s) constant next
  to the expiry policy, recording the IBEX account-type limit.
- Clamp every IBEX receive invoice centrally in the Ibex client's addInvoice
  wrapper via cappedIbexReceiveExpiration, so no caller can request more.
- Default the USD receive flows to 60s instead of 300s.
- Cover the policy with unit tests, including a regression guard that a
  5-minute (300s) request can never reach IBEX.

The mobile receive countdown already decodes the actual BOLT11 expiry, so
no client change is required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@linear

linear Bot commented Jun 18, 2026

Copy link
Copy Markdown

ENG-427

@islandbitcoin islandbitcoin self-assigned this Jun 18, 2026
@islandbitcoin

Copy link
Copy Markdown
Contributor Author

Merging. ✅

Final pre-merge check: approved, mergeable, and the relevant CI gates pass — Unit test (the new policy tests run green), check-secret, Check Schema, GraphQL Inspector, and CodeQL.

The red checks (Check Code, Spell Check, Audit, Bats, Integration test, Quickstart) were each inspected and are pre-existing failures unrelated to this change:

  • Check Code (tsc) fails only in pre-existing integration specs (offers/execute-offer, offers/make-cashout-offer, wallet/external-wallet — the currency-field mismatch); none of this PR's files error.
  • Spell Check flags repo-wide typos (Governement, Aggrement, Writeable, …); none introduced here.

Cleanup pass also confirmed no orphaned defaultUsdExpiration (still used by the no-amount paths).

@islandbitcoin islandbitcoin merged commit 58a32e2 into main Jun 19, 2026
8 of 14 checks passed
@islandbitcoin islandbitcoin deleted the jabariennis/eng-427-fixflash-align-ibex-receive-invoice-ux-with-60s-expiry-limit branch June 19, 2026 16:23
heyolaniran pushed a commit to heyolaniran/flash that referenced this pull request Jun 20, 2026
…lash#410)

Flash uses non-msat IBEX currency accounts (USD/USDT/JMD) for its receive
flows, which IBEX limits to a 60s BOLT11 expiry; only msat accounts allow
up to 900s. The backend defaulted to 5 minutes (300s) and IBEX silently
capped that down to 60s, so the requested value was never honored.

- Add a documented IBEX_RECEIVE_MAX_EXPIRATION_SECONDS (60s) constant next
  to the expiry policy, recording the IBEX account-type limit.
- Clamp every IBEX receive invoice centrally in the Ibex client's addInvoice
  wrapper via cappedIbexReceiveExpiration, so no caller can request more.
- Default the USD receive flows to 60s instead of 300s.
- Cover the policy with unit tests, including a regression guard that a
  5-minute (300s) request can never reach IBEX.

The mobile receive countdown already decodes the actual BOLT11 expiry, so
no client change is required.

Co-authored-by: Dread <bobodread@bobodread.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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