Skip to content

feat(ramps): add Tron amount validation on BuildQuote screen [DRAFT] - #39206

Draft
wantedsystem wants to merge 1 commit into
mainfrom
cursor/tron-offramp-amount-validation-66eb
Draft

wantedsystem wants to merge 1 commit into
mainfrom
cursor/tron-offramp-amount-validation-66eb

Conversation

@wantedsystem

Copy link
Copy Markdown
Contributor

Description

Draft PR: Continues non-EVM (Tron) work in the Ramps off-ramp (Sell) flow by adding debounced balance-only validation on the amount input screen (BuildQuote) and wiring the Max button to the Snap's getMaxSendableAmount method.

Depends on:

These Snap PRs must be merged and released before this can be merged.

What's Done

✅ BuildQuote screen validation:

  • Debounced (500ms) Tron amount validation via onAmountInput without toAddress
  • Inline error display (insufficient balance / insufficient balance to cover fee)
  • Continue button disabled while validating or when validation error present
  • All behind rampsOffRampNonEvm feature flag

✅ Max button integration:

  • Max button for Tron calls Snap's getMaxSendableAmount
  • Safe fallback to balance-based calculation if Snap method unavailable
  • Works for both native TRX and TRC-20 tokens (e.g., USDT)

✅ Core utilities:

  • getMaxSendableTronAmount function in core/Multichain/tron.ts
  • validateTronTransferAmount now accepts optional toAddress for balance-only validation
  • New useTronAmountValidation hook with debounce and error mapping

✅ Tests:

  • Unit tests for getMaxSendableTronAmount (5 test cases)
  • Unit tests for validateTronTransferAmount with optional toAddress (1 test case)
  • Unit tests for useTronAmountValidation hook (8 test cases)

✅ Compilation:

  • TypeScript compilation passes
  • Linter passes
  • Tests pass

What's NOT Done (Follow-ups)

❌ Integration with existing pre-send validation:

❌ Additional features:

  • Display estimated fees and resources breakdown on BuildQuote screen
  • Re-validate when screen regains focus
  • Separate analytics events for pre-validation failures vs user rejections

❌ Other non-EVM chains:

  • This PR only handles Tron; Solana and other non-EVM chains unchanged

Technical Details

Files Changed:

  • app/core/Multichain/tron.ts: Added getMaxSendableTronAmount, made toAddress optional in validateTronTransferAmount
  • app/components/UI/Ramp/Aggregator/hooks/useTronAmountValidation.ts: New debounced validation hook
  • app/components/UI/Ramp/Aggregator/Views/BuildQuote/BuildQuote.tsx: Integrated validation, wired Max button
  • app/components/UI/Ramp/Aggregator/Views/BuildQuote/BuildQuote.testIds.ts: Added TRON_VALIDATION_ERROR test ID
  • locales/languages/en.json: Added tron_validation.validation_unavailable string
  • Tests: app/core/Multichain/test/tron.test.ts, app/components/UI/Ramp/Aggregator/hooks/useTronAmountValidation.test.tsx

Snap API Contract:

  • onAmountInput({ accountId, assetId, value, toAddress? }): When toAddress is omitted, returns conservative fee estimate (probes to Tron zero address, includes activation reserve for native TRX)
  • getMaxSendableAmount({ accountId, assetId, toAddress? }): Returns { maxAmount, balance, fees, valid, errors }

Gated:

  • All new behavior is behind the existing rampsOffRampNonEvm feature flag
  • EVM and Solana off-ramp flows unchanged

Changelog

CHANGELOG entry:
feat: Added Tron amount validation with inline errors and Max button integration on the Sell (off-ramp) amount screen

Related issues

N/A (continuation of PR #38249)

Manual testing steps

Feature: Tron off-ramp amount validation on BuildQuote

  Background:
    Given the rampsOffRampNonEvm flag is on
    And the user has a Tron account with TRX

  Scenario: user types an amount below their balance
    When user selects Sell and chooses Tron TRX
    And user types "10" TRX
    Then after 500ms, no validation error is shown
    And Continue is enabled

  Scenario: user types an amount exceeding balance minus fees
    When user selects Sell and chooses Tron TRX
    And user types an amount close to their full balance
    Then after 500ms, a validation error is shown
    And Continue is disabled

  Scenario: user taps Max for Tron
    When user selects Sell and chooses Tron TRX
    And user taps Max
    Then the amount is set to the Snap's maxAmount
    And validation passes

  Scenario: Snap method unavailable
    Given the Snap does not support getMaxSendableAmount
    When user taps Max for Tron
    Then the amount falls back to balance-based calculation

Screenshots/Recordings

N/A (draft PR, not ready for visual review)

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs and MetaMask Mobile Coding Standards
  • I've completed the PR template to the best of my ability
  • I've included tests if applicable
  • I've documented my code using JSDoc format if applicable
  • I've applied the right labels on the PR

Performance checks (if applicable)

  • I've tested on Android
  • I've tested with a power user scenario
  • I've instrumented key operations with Sentry traces

Pre-merge reviewer checklist

  • I've manually tested the PR
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots

Note: This is a DRAFT PR. Do not mark ready for review until internal-snaps #554 and #549 are merged and released.

Open in Web Open in Cursor 

Add debounced balance-only validation for Tron assets on the Sell
amount input screen (BuildQuote), and wire the Max button to use the
Snap's getMaxSendableAmount method for precise fee-aware amounts.

Changes:
- core/Multichain/tron.ts: Add getMaxSendableTronAmount function,
  make toAddress optional in validateTronTransferAmount for balance-only
  validation
- Aggregator/hooks/useTronAmountValidation: New debounced validation
  hook that calls onAmountInput without toAddress after 500ms
- BuildQuote: Integrate Tron validation hook, show inline error,
  disable Continue button when validation fails, wire Max to Snap's
  getMaxSendableAmount with fallback
- tests: Unit tests for tron.ts additions and useTronAmountValidation
  hook (8 test cases covering debounce, error states, and cancellation)

All gated behind rampsOffRampNonEvm feature flag. EVM and other non-EVM
(Solana) behavior unchanged.

Depends on internal-snaps #554 (onAmountInput conservative estimates)
and #549 (getMaxSendableAmount) being merged and released.

Co-authored-by: Amine Harty <wantedsystem@users.noreply.github.com>
@github-actions github-actions Bot added the size-L label Nov 9, 2026
@metamask-ci metamask-ci Bot added team-emerging-opportunities INVALID-PR-TEMPLATE PR's body doesn't match template labels Nov 9, 2026
@metamask-ci

metamask-ci Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

PR template — items to address before "Ready for review"

Warnings — informational, address before merging:

See docs/readme/ready-for-review.md for the full Definition of Ready for Review.

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Smart E2E Test Selection

Selected E2E tags: ALL

AI Confidence: 100

E2E reasoning

Expand to read

Hard rule floor (en-locale-change): locales/languages/en.json adds a new tron_validation.validation_unavailable string that feeds UI text/label selectors used in E2E tests — this mandates ALL tags per the hard rule seed.

Beyond the locale change, the PR introduces:

  1. BuildQuote.tsx (Ramp/Buy flow): Integrates Tron amount validation, adds a new error display (TRON_VALIDATION_ERROR), disables the CTA when Tron validation fails, and adds async handling for quick amounts with Tron max amount calculation. This directly affects the SmokeMoney buy/sell flow.
  2. app/core/Multichain/tron.ts (CRITICAL path): Adds getMaxSendableTronAmount and makes toAddress optional in validateTronTransferAmount. Tron is a non-EVM chain affecting SmokeNetworkExpansion.
  3. useTronAmountValidation.ts: New hook consumed by BuildQuote for Tron-specific validation in the Ramp flow.
  4. BuildQuote.testIds.ts: Adds TRON_VALIDATION_ERROR test ID constant — any E2E test using BuildQuote selectors could be affected.

The combination of a locale change (hard rule), modifications to the core Ramp BuildQuote view (SmokeMoney), and Multichain/Tron changes (SmokeNetworkExpansion) justifies running ALL smoke tags. The locale change alone is sufficient to trigger the ALL floor per the hard rule.

View run

Copy link
Copy Markdown
Contributor

Accessibility (draft)

Since this is still a draft, no rush here, just a heads-up for when you wrap it up.

One spot in BuildQuote.tsx would leave a screen reader user guessing:

  • When the Tron validation error appears (BuildQuote.tsx:1200-1207), Get quotes turns disabled but the error text itself is never read out, so they'd only hear a dimmed button with no reason. Giving that error Text accessibilityRole="alert" and calling AccessibilityInfo.announceForAccessibility(tronValidationError) when it changes would cover both iOS and Android (WCAG 4.1.3).

An AI accessibility agent posted this. If this is wrong, reply here.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants