Add PocketChange UI for Monero wallet#5941
Add PocketChange UI for Monero wallet#5941claudinethelobster wants to merge 2 commits intoEdgeApp:developfrom
Conversation
- Create PocketChangeModal component with toggle and slider - Add English localization strings for PocketChange - Modal allows enabling/disabling and configuring pocket amount (0.1-1.3 XMR) - Integrates with Airship modal system Integration TODO: - Add modal trigger to Monero wallet settings/menu - Update SendScene to call wallet.otherMethods.getPocketChangeTargetsForSpend() - Show pocket breakdown in send confirmation - Save config to wallet.walletLocalData.pocketChangeSetting
fixup! Add PocketChange UI components and strings Co-authored-by: Cursor <cursoragent@cursor.com>
Replaced by review with inline comments
eddy-edge
left a comment
There was a problem hiding this comment.
Additional Findings
- critical: Unsquashed
fixup!commit present:7dfda3616 fixup! Add PocketChange UI components and strings. Fixup commits must be squashed before merging.- Run
git rebase -i --autosquash HEAD~2to squash the fixup intoacda95216, then force-push.
- Run
| import { EdgeText, Paragraph } from '../themed/EdgeText' | ||
| import { EdgeModal } from './EdgeModal' | ||
|
|
||
| const POCKET_AMOUNTS_XMR = [0.1, 0.2, 0.3, 0.5, 0.8, 1.3] |
There was a problem hiding this comment.
Issue: Floating-point numbers used for crypto amounts: POCKET_AMOUNTS_XMR = [0.1, 0.2, 0.3, 0.5, 0.8, 1.3]. JavaScript IEEE-754 floats are imprecise and should never be used to represent cryptocurrency denominations.
Recommendation: Store amounts as strings in the coin's smallest unit (piconero for XMR), or at minimum as integer multipliers of a fixed base unit. Convert to display strings using the same div/bignum helpers used elsewhere in the codebase (e.g., div(nativeAmount, multiplier, DECIMAL_PRECISION)).
| ] | ||
|
|
||
| export function WalletListMenuModal(props: Props) { | ||
| export function WalletListMenuModal(props: Props): React.ReactElement { |
There was a problem hiding this comment.
Warning: WalletListMenuModal is exported as a plain function declaration (export function WalletListMenuModal(props: Props): React.ReactElement) rather than the project-convention React.FC<Props> pattern.
Recommendation: Change to export const WalletListMenuModal: React.FC<Props> = props => { ... }
| const styles = getStyles(theme) | ||
|
|
||
| const handleCancel = () => { | ||
| const handleCancel = (): void => { |
There was a problem hiding this comment.
Warning: handleCancel is a plain arrow function not wrapped in useHandler, inconsistent with all other handlers in this file and the codebase convention.
Recommendation: Wrap with useHandler: const handleCancel = useHandler((): void => { props.bridge.resolve() })
| result != null && | ||
| wallet.otherMethods?.setPocketChangeSetting != null | ||
| ) { | ||
| await wallet.otherMethods.setPocketChangeSetting(result) |
There was a problem hiding this comment.
Warning: In the pocketChange success path, setLoadingOption(null) is never called before bridge.resolve(). If the modal stays mounted briefly (animation, test), the loading spinner remains stuck. The error path correctly resets it.
Recommendation: Add setLoadingOption(null) before bridge.resolve() in the success path, or use a finally block.
| await wallet.otherMethods.setPocketChangeSetting(result) | ||
| } | ||
| bridge.resolve() | ||
| } catch (error) { |
There was a problem hiding this comment.
Warning: catch (error) is missing the unknown type annotation, leaving error implicitly typed as any.
Recommendation: Change to catch (error: unknown).
| pocketchange_per_pocket: 'per pocket', | ||
| pocketchange_explainer: | ||
| 'When enabled, received funds will automatically be split into pockets of the selected size.', | ||
| pocketchange_menu_item: 'Pocket Change', |
There was a problem hiding this comment.
Suggestion: pocketchange_menu_item and pocketchange_line_item both have the identical value 'Pocket Change'. Two keys for the same string means translators must translate it twice.
Recommendation: Evaluate whether both usage sites truly need independent strings. If not, consolidate to a single key (e.g., reuse pocketchange_title).
| } | ||
| } | ||
|
|
||
| // Expand spend targets with pocket change outputs if supported |
There was a problem hiding this comment.
Suggestion: The comment // Expand spend targets with pocket change outputs if supported describes what the code does (obvious) rather than why. The protocol contract (otherParams?.isPocketChange === true) is undocumented.
Recommendation: Replace with a why-comment documenting the protocol: e.g., 'The plugin may append extra change outputs to minimise UTXO dust. Plugin-added outputs are tagged with otherParams.isPocketChange === true so the UI can display them separately.'
|
|
||
| <View style={styles.stepperRow}> | ||
| <EdgeButton | ||
| label="−" |
There was a problem hiding this comment.
Suggestion: "−" and "+" button labels are hardcoded strings not sourced from locale strings.
Recommendation: Add pocketchange_decrease / pocketchange_increase keys (or reuse existing generic symbols) in both locale files and reference via lstrings.
| setEnabled(prev => !prev) | ||
| }) | ||
|
|
||
| const handleDecrease = useHandler((): void => { |
There was a problem hiding this comment.
Suggestion: No unit tests cover the stepper bounds logic (handleDecrease, handleIncrease) or the Save/Cancel flow.
Recommendation: Add a test file at src/__tests__/modals/PocketChangeModal.test.tsx covering: initial state, upper bound clamping, lower bound clamping, Save resolving with config, Cancel resolving with undefined.
|
|
||
| // Expand spend targets with pocket change outputs if supported | ||
| let finalSpendInfo = spendInfo | ||
| if (coreWallet.otherMethods?.getPocketChangeTargetsForSpend != null) { |
There was a problem hiding this comment.
Suggestion: The pocket-change expansion path in the makeSpend effect has no test coverage. Only the fallback (else branch) is implicitly covered by existing tests that use wallets without getPocketChangeTargetsForSpend.
Recommendation: Add a test with a fake wallet mock that provides getPocketChangeTargetsForSpend, asserting that pocketChangeTargets is populated with only isPocketChange-tagged targets and that finalSpendInfo.spendTargets is expanded correctly.
Overview
Adds UI components and localization for PocketChange feature. This PR provides the user-facing interface for configuring PocketChange settings. Requires: edge-currency-monero PR #101 for core functionality.
Changes
New Components
src/components/modals/PocketChangeModal.tsx:PocketChangeConfiginterfacesrc/locales/strings/enUS.json:Integration Requirements (Not Yet Implemented)
This PR provides the UI scaffolding. The following integration work is still needed:
1. Add Settings Menu Trigger
Option A: Wallet List Menu (Recommended)
Edit:
src/components/modals/WalletListMenuModal.tsxAdd menu item for Monero wallets:
Add action in
src/actions/WalletListMenuActions.ts:2. Integrate into Send Flow
Edit:
src/components/scenes/SendScene.tsxorSendScene2.tsxBefore creating the spend:
3. Update Send Confirmation UI
Edit:
src/components/scenes/SendConfirmationScene.tsxShow pocket breakdown:
Testing
After integration is complete:
Enable PocketChange:
Send Transaction:
Verify Immediate Spend:
Related
Files Modified
src/components/modals/PocketChangeModal.tsx- NEW (103 lines)src/locales/strings/enUS.json- 11 new stringsFiles Requiring Integration (TODO)
src/components/modals/WalletListMenuModal.tsxORsrc/components/scenes/CurrencySettingsScene.tsxsrc/actions/WalletListMenuActions.tssrc/components/scenes/SendScene.tsx(orSendScene2.tsx)src/components/scenes/SendConfirmationScene.tsxNotes
This PR is intentionally minimal (UI components only) to keep the review scope manageable. Integration work can be done as a follow-up or included before merge depending on preference.