Skip to content

feat(send): preflight balance check at input time#1098

Open
orveth wants to merge 1 commit into
masterfrom
feat/preflight-balance
Open

feat(send): preflight balance check at input time#1098
orveth wants to merge 1 commit into
masterfrom
feat/preflight-balance

Conversation

@orveth

@orveth orveth commented May 20, 2026

Copy link
Copy Markdown
Contributor

Closes #425.

  • Synchronous client-side check that the entered amount exceeds the source account's balance. Assumes zero fee — real fee enforcement stays server-side in the quote services.
  • Covers every input moment where the amount is known client-side: numpad input, pasted bolt11 with embedded amount, scanned bolt11 with embedded amount, hash-based deep-link entry.
  • Shared exceedsAccountBalance helper at app/features/send/balance-check.ts, consumed by send-input.tsx and send-scanner.tsx.
  • Skips the check (returns false) when balance is unknown (Spark account still syncing) — better to attempt the send than block on missing data.
  • Cross-currency reuses the existing inputValue / convertedValue pair; no new converter.

UX:

  • Inline "Insufficient balance" replaces the converted-money switcher while overage is active.
  • Numpad shake fires on the false -> true transition (via useEffect + useRef on previous value) — not on every keypress while over.
  • Continue button disabled while insufficient.
  • Paste / scan with embedded amount > balance: destructive toast, user lands on /send with destination chip intact.

@vercel

vercel Bot commented May 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agicash Ready Ready Preview, Comment Jun 5, 2026 10:17pm

Request Review

@supabase

supabase Bot commented May 20, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project hrebgkfhjpkbxpztqqke because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

<PageFooter className="sm:pb-14">
<Numpad
showDecimal={maxInputDecimals > 0}
onButtonClick={(value) => {

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.

@claude can you revert this diff on these lines

@claude claude Bot May 21, 2026

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.

Claude finished @gudnuf's task in 1m 27s —— View job


Reverted numpad formatting change

  • Locate the diff at app/features/send/send-input.tsx:276
  • Revert the onButtonClick arrow-function formatting change
  • Run bun run fix:all to verify
  • Commit and push

Restored the original (value) => { handleNumberInput(value, startShakeAnimation); } block-body in app/features/send/send-input.tsx (was changed to an expression body — a pure formatting change unrelated to the preflight balance feature). Pushed as 8b11655.
· branch: feat/preflight-balance

@gudnuf gudnuf self-assigned this May 21, 2026
@gudnuf gudnuf requested a review from jbojcic1 May 21, 2026 16:46
@gudnuf gudnuf marked this pull request as ready for review May 21, 2026 16:46
onSwitch={switchInputCurrency}
money={convertedValue}
/>
{insufficientBalance ? (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i would rather show this somehow without hiding exchange rate

@@ -262,7 +295,7 @@ export function SendInput() {
<div className="flex items-center justify-end">
<Button
onClick={() => handleContinue(inputValue, convertedValue)}
disabled={inputValue.isZero()}
disabled={inputValue.isZero() || insufficientBalance}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i wonder if we should allow click but then show insufficient balance toast instead of showing it on every amount change?

@@ -68,6 +69,20 @@ export default function SendScanner() {

const convertedAmount =
amount.currency !== sendAccount.currency ? convert(amount) : undefined;

if (exceedsAccountBalance(amount, convertedAmount, sendAccount)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is related to my comment on that other pr that changes send scanner and it kind of proves my point there. now scanner becomes even more aware of something it shouldn't be its resposibility

sendAccount,
);

const wasInsufficient = useRef(false);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why is ref needed?

Rebased onto post-monorepo master; paths relocated app/ -> apps/web-wallet/app/. Original commits:
 - feat(send): preflight balance check at input time
 - refactor(send): shake inline on numpad keypress
 - chore(send): drop balance-check unit tests
 - refactor(send): drop dead check + tighten balance-check JSDoc
 - docs(send): reword balance-check JSDoc
 - refactor(send): expose previewNext, shake on balance-transition only
 - Revert "refactor(send): expose previewNext, shake on balance-transition only"
 - fix(send): shake on balance-transition via useEffect
 - revert(send): restore numpad onButtonClick arrow-body formatting
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.

Send flow should check available balance

3 participants