Skip to content

feat(keyboard): fill amounts from the right on the on-screen keypad - #1074

Merged
Kukks merged 2 commits into
masterfrom
split/p02-keypad-rtl
Oct 19, 2026
Merged

Kukks merged 2 commits into
masterfrom
split/p02-keypad-rtl

Conversation

@Kukks

@Kukks Kukks commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

The phone keypad enters digits right to left in the mode's smallest step, like a cash register: 1 2
shows 0.00000012 BTC, or $0.12 in USD. There is no decimal-point key. Typing stops at the digit cap,
a digit that would pass 21 M BTC is refused, and a balance loaded past the cap stays exact. The digit
logic lives in lib/keypadEntry.ts. A precision change with the same digits (a fiat or asset with other
decimals) recomputes the amount at once, not on the next key.

The e2e helpers type amounts in the mode's smallest step: handleKeyboardInput(page, value, decimals),
and prePay(..., decimals).

  • In: the keypad and its unit and e2e coverage.
  • Out: the title/subtitle props, which Receive's "Set an amount first" uses; they come with the
    receive redesign.

Test plan

  • tsc 0, lint 0.
  • keyboard + keypadEntry: 28 tests.
  • pnpm test:unit: 102 files / 997 tests (CI at f21862a).
  • CI e2e: keyboard, send, receive.

Dependencies: none. The receive redesign merges this in.

Split out of #1068.


Split series — supersedes #1000 and #1068; each PR is one feature. Base master unless noted:

Summary by CodeRabbit

  • New Features
    • Updated the amount keypad to enter values digit by digit, with decimal places determined by the selected currency or unit. For example, entering 199 in a two-decimal currency displays 1.99.
    • Removed the decimal-point key; use digit keys to enter fractional amounts.
    • Added amount limits for bitcoin and satoshi entry, and improved display of leading zeroes in bitcoin mode.
    • Amounts now convert appropriately when switching units or selecting the maximum balance.

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bfd7c659-404f-45a5-9a6b-7fe662a18939
📥 Commits

Reviewing files that changed from the base of the PR and between 86df35b and f21862a.

📒 Files selected for processing: 8
  • src/components/Keyboard.tsx
  • src/lib/keypadEntry.ts
  • src/test/components/keyboard.test.tsx
  • src/test/e2e/keyboard.test.ts
  • src/test/e2e/receive.test.ts
  • src/test/e2e/send.test.ts
  • src/test/e2e/utils.ts
  • src/test/lib/keypadEntry.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The keyboard now stores entered amounts as digits and formats them using the active mode’s decimal precision. It converts initial, maximum-balance, and toggled values into that representation, removes the decimal-point key, and updates component and end-to-end test coverage.

Changes

Keypad Amount Entry

Layer / File(s) Summary
Digit conversion and limits
src/lib/keypadEntry.ts, src/test/lib/keypadEntry.test.ts
Added digit insertion and removal, value formatting and conversion, a decimal-dependent digit limit, and a maximum-satoshi limit. Tests cover these operations and limits.
Keyboard state and display
src/components/Keyboard.tsx, src/test/components/keyboard.test.tsx
Keyboard input and amount conversions now use digit state. Bitcoin and sats entry apply MAX_SATS. The decimal key is replaced by a blank cell, and tests cover entry, backspacing, maximum selection, and unit toggling.
Mobile keypad entry tests
src/test/e2e/keyboard.test.ts, src/test/e2e/receive.test.ts, src/test/e2e/send.test.ts, src/test/e2e/utils.ts
End-to-end helpers accept decimal precision and format values as keypad digits. Mobile tests pass precision for fiat entry and check right-to-left digit input.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Suggested reviewers: bordalix

Merge Risk: ⚪ Minimal · up to f2186

The keypad now fills amounts from the right using digit-based entry. No concrete merge-blocking issue was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 8 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: keypad amounts now fill from the right on the on-screen keyboard.
  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Deploying wallet-bitcoin with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3741ebf
Status: ✅  Deploy successful!
Preview URL: https://a436c9d2.wallet-bitcoin.pages.dev
Branch Preview URL: https://split-p02-keypad-rtl.wallet-bitcoin.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Deploying wallet-mutinynet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3741ebf
Status: ✅  Deploy successful!
Preview URL: https://290f75f2.arkade-wallet.pages.dev
Branch Preview URL: https://split-p02-keypad-rtl.arkade-wallet.pages.dev

View logs

@arkana-ai-bot arkana-ai-bot 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.

Arkana review — PR #1074 · keypad right-to-left entry

No protocol-critical paths touched (no VTXO/signing/forfeit/round/exit). Overall this is a clean, well-scoped change. The digit-model abstraction in keypadEntry.ts is solid and the 28-test unit suite gives good edge-case coverage. A few items worth addressing before the receive-redesign merge lands.


Issues

1. amountInSats effect: missing fiatDecimals-driven invalidation (src/components/Keyboard.tsx)

// new deps: [digits, inputMode]
useEffect(() => {
  const strValue = textValue.replaceAll(',', '')  // textValue derived from digits + fiatDecimals()
  ...
}, [digits, inputMode])

textValue is digitsToValue(digits, getMaxDecimals()) and getMaxDecimals() calls fiatDecimals() when inputMode === 'fiat'. If the fiat context changes decimal precision (e.g., USD→JPY mid-session) while digits and inputMode are unchanged, textValue will update on the next render but the effect won't fire — leaving amountInSats stale until the user types another digit or toggles mode.

In practice the currencyConversionUseful effect clears digits on a currency context change, so the window is narrow. But the dependency is technically incomplete. The safest minimal fix is to include textValue in the deps array:

}, [digits, inputMode, textValue])

textValue is a render-derived string, so adding it is safe and makes the deps honest.


2. valueToDigits silently truncates excess fractional digits (src/lib/keypadEntry.ts, line 24)

frac.padEnd(decimals, '0').slice(0, decimals)

If frac is longer than decimals the extra digits are dropped without warning. The test at keypadEntry.test.ts line 57 ('1.234567891' → '123456789' at 8 decimals) confirms this is intentional. All current callers produce strings with at most decimals fractional digits (via toFixed, prettyNumber, or atomicToUnits), so there is no current caller-side bug. The behaviour should be documented in the JSDoc since a future caller passing a raw float string could lose precision silently.


3. Existing form.test.ts / bip21.test.ts callers — verified correct, no action needed

handleKeyboardInput(page, 2100) (default decimals = 0): (2100).toFixed(0) → '2100' → same digit sequence as the old sats.toString() path. All sats-denominated callers that omit decimals behave identically to before. ✓


Observations (no action required)

btcPrimary regex (Keyboard.tsx, line 167): /^[0.]*/ correctly grays out the insignificant leading zeros/dot in BTC display. digitsToValue always produces well-formed strings so no surprising match is reachable in practice.

pushDigit with maxUnits (keypadEntry.ts, line 11): BigInt(digits + key) is safe because the guard digits === '' && key === '0' → return '' fires before this path, so digits + key is always a non-empty decimal string when BigInt() is called.

Asset mode has no satoshi cap — only maxEntryDigits bounds it. That is correct; the over-balance guard handles the asset-specific limit at display time.

handleToggleCurrency sets digits and inputMode in the same synchronous event — React 18 batches these, so the single re-render sees both values together. No tearing.


Nits

  • Keyboard.tsx line 170: getMaxDecimals is called on every render to derive textValue; a useMemo or useCallback would make the dependency chain clearer, though not a correctness concern for a keyboard component.
  • keypadEntry.ts line 3 (maxEntryDigits) JSDoc could note that the 12-digit whole-part floor is intentional for 0-decimal (sats) mode.

@Kukks

Kukks commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

@arkana-ai-bot thanks.

  1. Effect deps: fixed in f21862ac. textValue is now a dependency of the amount effect, so a precision change with the same digits recomputes the amount.
  2. valueToDigits truncation: documented in f21862ac. The function's comment now says fraction digits past decimals are dropped. I kept that to one line, since every caller passes at most decimals digits, as you note.

On the nits, I left both as they are:

  • getMaxDecimals memo: it is a cheap switch, and memoising it would add a dependency chain without changing correctness.
  • maxEntryDigits doc: its comment already gives the scale-with-decimals intent. The 16-digit floor is what sats mode needs, because MAX_SATS is 16 digits.

@arkana-ai-bot

arkana-ai-bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Thanks, @Kukks — both fixes confirmed in f21862ac:

  • textValue dep (Keyboard.tsx line 118): textValue is now in the effect's deps array. ✓
  • valueToDigits comment (keypadEntry.ts line 24): the updated comment explicitly states that excess fraction digits are dropped. ✓

The rationale on the two nits makes sense. Correction on my end: I wrote "12-digit floor" in the maxEntryDigits nit, but 16 digits is correct — MAX_SATS is 21 000 000 × 10⁸ = 2 100 000 000 000 000, which is 16 digits. Good catch.

Nothing blocking from my side.

@arkana-ai-bot arkana-ai-bot 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.

Arkana follow-up review — PR #1074 f21862a

One commit since last pass; both prior issues are now closed. No new findings.

Prior issue status

1. amountInSats effect missing textValue dependency — Fixed in f21862a.
Keyboard.tsx line 118: dependency array is now [digits, inputMode, textValue]. A precision change with unchanged digits will correctly recompute the amount.

2. valueToDigits silent truncation undocumented — Fixed in f21862a.
keypadEntry.ts line 24 comment now states that excess fraction digits past decimals are dropped. Contract is now visible to future callers.

No new concerns in this diff. Change is ready from my side.

@Kukks

Kukks commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@Kukks
Kukks changed the base branch from ts-sdk-0.5 to master October 18, 2026 17:25
Kukks added 2 commits October 18, 2026 19:33
The phone keypad now enters digits right to left in the mode's smallest
step, like a cash register: typing 1 2 in BTC shows 0.00000012, and in USD
$0.12. There is no decimal-point key any more. Over-long values clamp
instead of being divided, a digit that would pass 21 M BTC is refused, and
a past-cap balance stays exact instead of turning into nines. The digit
logic lives in lib/keypadEntry.ts with its own tests.

The e2e helpers type amounts in the mode's smallest step: pass the mode's
decimals (2 for USD) so 2 becomes $2.00 rather than $0.02.

Split out of #1068.
…changes

The sats/asset amount effect read textValue but only listed digits and
inputMode, so a precision change (fiat decimals, asset decimals) with
the same digits left the amount stale until the next key. textValue is
now a dependency. valueToDigits' comment also notes that fraction digits
past the precision are dropped.
@Kukks
Kukks force-pushed the split/p02-keypad-rtl branch from f21862a to 3741ebf Compare October 18, 2026 17:57

@arkana-ai-bot arkana-ai-bot 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.

Arkana follow-up review — PR #1074 · 3741ebf

Status: Branch was force-pushed / rebased onto a newer master since last pass (commits ad6235e1 SDK 0.5 upgrade and da59fe99 sdk rc.24/swap rc.27 are now in the branch history). The keyboard feature code itself is byte-for-byte identical to the previous reviewed tree. Both prior issues remain Fixed; no new findings.


Prior issue status

1. amountInSats effect: missing textValue dependency — Fixed (confirmed in rebased 3741ebf1).
Keyboard.tsx hunk line }, [digits, inputMode, textValue] is present in the rebased commit, same as f21862ac.

2. valueToDigits silent truncation undocumented — Fixed (confirmed in rebased 3741ebf1).
keypadEntry.ts: comment reads "excess fraction digits drop" — contract is visible to future callers, same as f21862ac.


Scope note on the large compare

gh api …/compare/f21862ac…3741ebf1 shows 117 files because f21862ac is no longer an ancestor of 3741ebf1 after the rebase; the symmetric diff pulls in everything from the SDK upgrade commits. The PR-level diff is still +265 / −100, all keyboard-scoped. The non-keyboard files are from #936 and #1087, already merged to master and separately reviewed there; they are out of scope for this PR.

No new concerns. Change is ready from my side.

@Kukks
Kukks merged commit 45fe390 into master Oct 19, 2026
8 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.

2 participants