Skip to content

[pull] main from MetaMask:main#318

Merged
pull[bot] merged 9 commits into
Reality2byte:mainfrom
MetaMask:main
Nov 12, 2025
Merged

[pull] main from MetaMask:main#318
pull[bot] merged 9 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Nov 12, 2025

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

huggingbot and others added 9 commits November 12, 2025 07:42
<!--

Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.

-->

## **Description**

This PR adds analytics tracking for social login failures to help
identify where and why failures occur during the OAuth login flow.

The implementation tracks failures at three stages:
1. **Provider login failures** - When users cancel or encounter errors
during the OAuth provider authentication step
2. **Token exchange failures** - When errors occur during the
authorization code to JWT token exchange
3. **Seedless authentication failures** - When errors occur during the
seedless authentication step

Each failure event includes contextual metadata:
- `account_type` - The type of account being created (e.g.,
`default_google`, `default_apple`)
- `is_rehydration` - Whether this is a rehydration flow (existing user
returning)
- `failure_type` - Whether the failure was due to user cancellation or
an error
- `error_category` - The specific stage where the failure occurred

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/SL-257

## **Manual testing steps**

1. Start a social login flow (Google or Apple)
2. Cancel the OAuth provider authentication dialog
3. Verify that a `SocialLoginFailed` event is tracked with
`failure_type: 'user_cancelled'` and `error_category: 'provider_login'`
4. Attempt a social login and simulate a network error during token
exchange
5. Verify that a `SocialLoginFailed` event is tracked with
`failure_type: 'error'` and `error_category: 'get_auth_tokens'`
6. Attempt a social login and simulate an error during seedless
authentication
7. Verify that a `SocialLoginFailed` event is tracked with
`failure_type: 'error'` and `error_category: 'seedless_auth'`

## **Screenshots/Recordings**

<!-- Not applicable - this is an analytics-only change with no UI
changes -->

### **Before**

<!-- N/A -->

### **After**

<!-- N/A -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] 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.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds SOCIAL_LOGIN_FAILED tracking with rehydration context across
provider login, token exchange, and seedless auth; updates OAuth login
API and tests accordingly.
> 
> - **Analytics**:
> - Add `SOCIAL_LOGIN_FAILED` event in
`core/Analytics/MetaMetrics.events.ts` and export mapping.
> - **OAuth** (`core/OAuthService/OAuthService.ts`):
> - Add `userClickedRehydration` to local state and
`#trackSocialLoginFailure` to emit `SOCIAL_LOGIN_FAILED` with
`account_type`, `is_rehydration`, `failure_type`, and `error_category`.
> - Invoke tracking on failures in `provider_login`, `get_auth_tokens`,
and `seedless_auth` stages; validate `id_token` earlier.
> - Change `handleOAuthLogin(loginHandler, userClickedRehydration)`
signature and wire usage.
> - **Onboarding** (`components/Views/Onboarding/index.js`):
>   - Pass rehydration flag to `handleOAuthLogin` (`!createWallet`).
> - **Tests**:
> - Update unit tests in `OAuthService.test.ts` and
`Onboarding/index.test.tsx` to reflect new `handleOAuthLogin` param and
event behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
37e8b08. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
This PR fixes styling for "unconfirmed" transaction status
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fixed styling for "unconfirmed" transaction status

## **Related issues**

Fixes: #21574
https://consensyssoftware.atlassian.net/browse/TMCU-158

## **Manual testing steps**

```gherkin
Feature: Send BTC

  Scenario: user sends BTC
    Given BTC is enabled

    When user initiates BTC transaction and navigates to Activity tab
    Then unconfirmed transaction with yellow/orange "Pending" status should appear
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**
<img width="395" height="835" alt="Screenshot 2025-11-07 at 13 53 14"
src="https://github.com/user-attachments/assets/e74b1b50-be28-4800-a1cc-6be00665d119"
/>

<!-- [screenshots/recordings] -->

### **After**
<img width="396" height="833" alt="Screenshot 2025-11-07 at 13 52 51"
src="https://github.com/user-attachments/assets/431a522f-0338-4b22-b39a-29d51d03dfca"
/>

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Maps `Unconfirmed` statuses to pending and enables overriding styles
on status text components; updates i18n and snapshots.
> 
> - **UI**:
>   - `app/components/Base/StatusText.js`:
> - `ConfirmedText`, `PendingText`, `FailedText` now accept optional
`style` prop merged with base styles.
> - Treat `"Unconfirmed"/"unconfirmed"` as pending in `StatusText`
switch.
> - **i18n**:
> - `locales/languages/en.json`: add `"transaction.unconfirmed":
"Pending"`.
> - **Tests**:
> - Update `TransactionDetails` snapshots to reflect array-based `style`
merging.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fa44247. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

PR to add trending tokens card. This should be under a feature flag(
selector `selectAssetsTrendingTokensEnabled`)

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: No functional changes, this is still under a feature
flag.

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->
<img width="425" height="858" alt="Screenshot 2025-11-11 at 18 09 58"
src="https://github.com/user-attachments/assets/ff394cf2-fbc8-4965-a2d1-e048eb1990ad"
/>



## **Pre-merge author checklist**

- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] 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](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduces a Trending Tokens UI section integrated into TrendingView
with a shared token logo hook, updates the trending fetch hook to
default to popular networks, and adds comprehensive tests and i18n.
> 
> - **UI (Trending)**:
> - **Trending Tokens Section**: New `TrendingTokensSection` with
`TrendingTokensList`, `TrendingTokenRowItem`, `TrendingTokenLogo`, and
`TrendingTokensSkeleton`, integrated into `TrendingView` (header tweak,
scroll container).
> - **Hooks**:
> - **New**: `useTokenLogo` for shared image loading/error/background
logic; refactors `PerpsTokenLogo` to use it.
> - **Updated**: `useTrendingRequest` now accepts optional `chainIds`,
defaults to popular networks via
`useNetworksByNamespace`/`useNetworksToUse`, sets initial loading to
true, and fixes debounce dependencies.
> - **Utils**:
> - Add formatting helpers `formatCompactUSD` and `formatMarketStats`
for market cap/volume.
> - **Tests**:
> - Add extensive unit tests and snapshots for new components/hooks and
updated trending request behavior.
> - **Localization**:
> - Update `en.json` with `trending.title`, `trending.view_all`, and
`trending.tokens` strings.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
49ddd1a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Ensure the Predict withdraw confirmation uses the entire balance if the
`Max` button is used.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes:
[#6156](MetaMask/MetaMask-planning#6156)
#22190

## **Manual testing steps**

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Ensure Predict withdraw Max uses the full balance converted to USD and
add a fixed 1:1 USD rate for Polygon USDCE.
> 
> - **Confirmations / Amounts**:
> - Convert Predict balance to USD via `tokenFiatRate` for withdraw
calculations and `Max` behavior; default rate falls back to `1`.
> - Refine max-percentage logic when pay token is missing or matches the
first required token.
> - **Token Fiat Rates**:
> - Return fixed `1` rate for `POLYGON_USDCE` on `POLYGON` when currency
is USD (alongside `ARBITRUM_USDC`).
>   - Minor refactor for USD checks and token matches.
> - **Alerts**:
> - Use human Predict balance in `useInsufficientPredictBalanceAlert`
comparison.
> - **Tests**:
> - Update and add tests for USDCE fixed rate and Predict withdraw USD
conversion/max behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f179f68. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Adjusted the funding tooltip copy in the position component to display
position-specific information. Previously, both the position card's
"Funding Cost" and the market statistics "Funding Rate" used the same
generic tooltip explaining funding rates. This change adds a dedicated
tooltip for funding payments that clarifies it represents the cumulative
amount paid/received since the position opened.

**Changes:**
- Added new `funding_payments` tooltip type
- Updated position card to use the new tooltip
- Market statistics continues to use the existing `funding_rate` tooltip

## **Changelog**

CHANGELOG entry: Updated funding tooltip in position component to show
position-specific information

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-1880

## **Manual testing steps**

```gherkin
Feature: Funding payments tooltip in position component

  Scenario: user views funding tooltip in position card
    Given user has an open perp position
    And the position card displays the "Funding" field with an info icon

    When user taps the info icon next to "Funding" in the position card
    Then the tooltip displays title "Funding payments"
    And the tooltip content reads "This is the amount you've paid in funding fees since the position was opened. Funding is paid or received every hour to keep the perp price close to the actual token price."

  Scenario: user views funding rate tooltip in market statistics
    Given user is viewing market statistics for a perp

    When user taps the info icon next to "Funding rate"
    Then the tooltip displays title "Funding rate"
    And the tooltip content describes the general funding rate concept
```

## **Screenshots/Recordings**

### **Before**

Position card showed generic funding rate tooltip (same as market
statistics)

### **After**

Position card shows position-specific funding payments tooltip with
cumulative payment context


https://github.com/user-attachments/assets/65db42a1-68fc-4758-950f-ad1dd79e1030


## **Pre-merge author checklist**

- [x] I've followed MetaMask Contributor Docs and MetaMask Mobile Coding
Standards
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable (N/A - localization change only)
- [x] I've documented my code using JSDoc format if applicable (N/A)
- [x] I've applied the right labels on the PR

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed)
- [ ] 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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduces a new `funding_payments` tooltip and switches the position
card’s funding info icon to use it, with corresponding registry and
locale updates.
> 
> - **Perps Tooltips**:
> - Add new content key `funding_payments` to `PerpsTooltipContentKey`
and register in `contentRegistry`.
> - **Position Card**:
> - Change funding info icon handler from `funding_rate` to
`funding_payments` in `PerpsPositionCard`.
> - **Localization**:
> - Add `perps.tooltips.funding_payments` strings (title and content) in
`en.json`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
2149df2. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

This PR enables back native token send. 

As it stated in the previous automated flaky test thread
[here](https://consensys.slack.com/archives/C02U025CVU4/p1762243312142959)
and the
[logs](https://github.com/MetaMask/metamask-mobile/actions/runs/19055429448/job/54425009493),
send native spec was failing. However if you look at the logs - this is
not entirely related as there is a detox crash.

I ran these tests over and over on local but I couldn't encoutner the
issue once, hence we are enabling it back.


https://github.com/user-attachments/assets/042fdb4f-c846-4e7c-92d9-6985798e3de0

**Update 1** 

We still encounter the issues in the CI - Ola [had a look but no
chance](https://consensys.slack.com/archives/C01U65ZUS2E/p1762787121323169?thread_ts=1762776032.589089&cid=C01U65ZUS2E).
Hence we are disabling this `50%` test rest looks good.

**Update 2** 

It appears the issues are because of `%` text. I changed e2e test to
lookup component test ids instead of text and it worked.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:  #22135

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [X] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I’ve included tests if applicable
- [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.




<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds testIDs to percentage buttons and updates send flow e2e selectors
to target them by ID.
> 
> - **UI**:
> - Add `testID` to percentage buttons in
`app/components/Views/confirmations/components/edit-amount-keyboard/edit-amount-keyboard.tsx`
as `percentage-button-<value>`.
> - **E2E Tests**:
> - Update `e2e/pages/Send/RedesignedSendView.ts` to select `50%` and
`Max` via
`getElementByID('percentage-button-50'|'percentage-button-100')` instead
of text.
> - Keep send native token spec logic the same while interacting with
the new IDs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
505718b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…tion cp-7.59.0 (#22252)

## **Description**

This PR implements a major refactor of the Perps order handling system
to address precision and validation issues. The changes establish USD as
the primary source of truth for order amounts, replacing the complex
`findOptimalAmount` optimization logic with a simpler, more robust
approach that recalculates position sizes at execution time using fresh
market prices.

### Key Changes

#### 1. Migration from `findOptimalAmount` to USD-as-Source-of-Truth

**Previous Approach:**
- Used `findOptimalAmount` function to find the "optimal" USD amount
that maximized value while maintaining the same position size
- Performed complex calculations with position size increments and
rounding
- Optimized order amounts on every input change (percentage, slider,
keypad, etc.)
- Position size was calculated once in the UI and used directly for
order placement

**New Approach:**
- **USD amount is now the primary source of truth** - stored and
validated as entered by user
- Position size is recalculated at execution time with the freshest
available price
- Eliminates complex optimization logic (~150 lines removed from
`orderCalculations.ts`)
- Simplified order form handling (~71 lines removed from
`usePerpsOrderForm.ts`)

**Benefits:**
- Eliminates edge cases where optimization could produce invalid orders
- Reduces computational overhead on every input change
- More predictable behavior - what user enters is what gets validated
and executed
- Better handling of price volatility during order placement

#### 2. Standardized Slippage Management

**New Configuration:**
```typescript
export const ORDER_SLIPPAGE_CONFIG = {
  DEFAULT_SLIPPAGE_BPS: 100, // 100 basis points = 1%
} as const;
```

**Improvements:**
- Unified slippage configuration using basis points for consistency
- Added price staleness validation to prevent execution with stale
prices
- New `priceAtCalculation` and `maxSlippageBps` fields in `OrderParams`
- Provider validates price hasn't moved beyond tolerance before
execution
- Standardized slippage across market orders, position closing, and
TP/SL orders

**Slippage Validation Example:**
```typescript
// Provider checks price delta before order execution
const priceDeltaBps = Math.abs(
  ((currentPrice - priceAtCalculation) / priceAtCalculation) * 10000
);
if (priceDeltaBps > maxSlippageBps) {
  throw new Error(`Price moved too much: ${priceDeltaBps} bps`);
}
```

#### 3. Enhanced Order Validation

**Validation Improvements:**
- **USD as source of truth for minimum validation** - validates user's
exact USD input without recalculation
- Example: User enters $10 → validates $10 directly (no rounding errors)
- For full position closes (e.g., Close All), minimum validation is
skipped
- Added `skipValidation` flag to prevent validation flash during keypad
input
- Enhanced limit order validation to require price parameter

**Type System Updates:**
```typescript
export type OrderParams = {
  // Existing fields...
  size: string; // Now derived, provider recalculates from usdAmount

  // New hybrid approach fields
  usdAmount?: string; // Primary source of truth
  priceAtCalculation?: number; // For slippage validation
  maxSlippageBps?: number; // Slippage tolerance (e.g., 100 = 1%)

  // Updated documentation
  slippage?: number; // Now defaults to ORDER_SLIPPAGE_CONFIG.DEFAULT_SLIPPAGE_BPS / 10000
};
```

#### 4. Close Position Validation & Precision

**Problem Addressed:**
- Close positions were failing with "Minimum order size is $10" even
when closing 100% of small positions (e.g., closing a $5.23 position)
- Close position calculations used hardcoded decimal precision (6
decimals) instead of asset-specific `szDecimals`
- As part of the USD-as-source-of-truth refactor, close position
calculations needed the same precision improvements as order placement

**Solution - Full vs Partial Close Distinction:**

**Full Position Close (100%):**
- Added `isFullClose` flag to `OrderParams` type
- Set automatically when `size` parameter is omitted: `isFullClose:
!params.size`
- Skips USD validation and $10 minimum entirely
- Allows closing positions of any size (e.g., $5.23 position)

**Partial Position Close:**
- Still enforces $10 minimum validation
- Uses same USD validation logic as new orders
- Requires `currentPrice` or `usdAmount` for validation

**Close Amount Calculation Refactor:**
- Migrated `calculateCloseAmountFromPercentage` to USD as source of
truth
- Added required `szDecimals` parameter (removed dangerous defaults)
- Implemented post-rounding USD validation:
  ```typescript
  const actualUsd = tokenAmount * currentPrice;
  if (actualUsd < usdValue) {
    tokenAmount += 1 / multiplier; // Add 1 minimum increment
  }
  ```
- Now matches `calculatePositionSize` logic for consistency

**Type Changes:**
```typescript
export type OrderParams = {
  // ... existing fields
  isFullClose?: boolean; // Indicates closing 100% of position (skips validation)
};

// calculateCloseAmountFromPercentage now requires szDecimals
interface CloseAmountFromPercentageParams {
  percentage: number;
  positionSize: number;
  currentPrice: number;
  szDecimals: number; // REQUIRED - no longer optional
}
```

**Files Changed:**
- `controllers/types/index.ts` - Added `isFullClose` flag
- `utils/positionCalculations.ts` - Refactored to use USD as source of
truth with asset-specific precision
- `Views/PerpsClosePositionView/PerpsClosePositionView.tsx` - Added
`szDecimals` handling with loading state
- `controllers/providers/HyperLiquidProvider.ts` - Updated validation to
skip minimum for full closes

#### 5. Position Size Calculation Changes

**Rounding Behavior:**
- Changed from `Math.floor` to `Math.round` in `calculatePositionSize`
- More accurate position size calculation that rounds to nearest value
- Aligned with provider's recalculation logic for consistency

**Provider-Side Recalculation:**
```typescript
// In HyperLiquidProvider.placeOrder()
if (params.usdAmount && parseFloat(params.usdAmount) > 0) {
  const usdAmount = parseFloat(params.usdAmount);

  // Recalculate with fresh price
  finalPositionSize = usdAmount / currentPrice;

  // Apply same rounding as UI
  const multiplier = Math.pow(10, assetInfo.szDecimals);
  finalPositionSize = Math.round(finalPositionSize * multiplier) / multiplier;
}
```

#### 6. User Experience Improvements

**Input Handling:**
- Removed optimization calls from percentage/slider/max buttons
- Fixed input clamping to only apply for keypad input (not
percentage/slider/max)
- Reduced unnecessary re-renders and calculations
- Skip validation during active input to prevent flickering error
messages

**Code Cleanup:**
- Removed FinalizationRegistry polyfill from `shim.js` (no longer needed
by updated dependencies)
- Removed unused `findOptimalAmount` and
`findHighestAmountForPositionSize` functions
- Cleaned up debounced optimization logic from form handlers

### Migration Path

**Backward Compatibility:**
- `size` field still present in `OrderParams` for backward compatibility
- Provider falls back to legacy size calculation if `usdAmount` is not
provided
- Existing orders and integrations continue to work

**Hybrid Approach:**
Orders now pass both `usdAmount` (primary) and `size` (derived):
```typescript
const orderParams: OrderParams = {
  coin: 'BTC',
  isBuy: true,
  size: positionSize, // Kept for compatibility, recalculated by provider
  usdAmount: orderForm.amount, // USD as source of truth
  priceAtCalculation: assetData.price, // For validation
  maxSlippageBps: 100, // 1% tolerance
  // ... other fields
};
```

### Files Changed

**Core Logic (276 additions, 290 deletions):**
- `app/components/UI/Perps/controllers/providers/HyperLiquidProvider.ts`
(+148 lines)
  - Hybrid USD-based order placement with price validation
  - Standardized slippage across all order types
  - Position size recalculation at execution time
- `app/components/UI/Perps/utils/orderCalculations.ts` (-149 lines)
  - Removed `findOptimalAmount` and `findHighestAmountForPositionSize`
  - Changed `Math.floor` to `Math.round` for position size calculation
- `app/components/UI/Perps/hooks/usePerpsOrderForm.ts` (-71 lines)
  - Removed `optimizeOrderAmount` function and related logic
  - Simplified amount initialization
- `app/components/UI/Perps/hooks/usePerpsOrderValidation.ts` (+28 lines)
  - Added `skipValidation` and `originalUsdAmount` parameters
  - Improved minimum order size validation with original USD input

**UI Components:**
- `app/components/UI/Perps/Views/PerpsOrderView/PerpsOrderView.tsx`
(+/-54 lines)
  - Removed optimization calls from input handlers
  - Added `skipValidation` flag during input focus
  - Pass `usdAmount` and price validation params to provider
  - Fixed input clamping behavior

**Configuration:**
- `app/components/UI/Perps/constants/perpsConfig.ts` (+10 lines)
  - Added `ORDER_SLIPPAGE_CONFIG` constant
- `app/components/UI/Perps/constants/hyperLiquidConfig.ts` (-1 line)
  - Removed legacy slippage configuration

**Types & Validation:**
- `app/components/UI/Perps/controllers/types/index.ts` (+9 lines)
  - Updated `OrderParams` type with USD-based fields
- `app/components/UI/Perps/utils/hyperLiquidValidation.ts` (+9 lines)
  - Enhanced validation for limit orders
  - Added minimum order size tolerance
- `app/components/UI/Perps/utils/hyperLiquidValidation.test.ts` (+29
lines)
  - Added tests for limit order price validation

**Cleanup:**
- `shim.js` (-18 lines)
  - Removed FinalizationRegistry polyfill

## **Changelog**

CHANGELOG entry: Improved Perps order precision and validation by using
USD amounts as source of truth and standardizing slippage management

## **Related issues**

Fixes:
[TAT-1902](https://consensyssoftware.atlassian.net/browse/TAT-1902) -
Investigate and resolve order placement issue for specific token pairs

**How this PR fixes TAT-1902:**
The USD-as-source-of-truth refactor directly addresses order placement
failures for specific token pairs by:
- Recalculating position size at execution time with fresh market prices
instead of using stale UI calculations
- Using asset-specific `szDecimals` precision throughout (no more
hardcoded 6 decimals)
- Eliminating optimization logic that could produce invalid amounts near
precision boundaries
- Validating orders with the exact USD amount entered by the user,
preventing precision loss from multiple conversions

This ensures orders are calculated with the most current price and
correct precision for each token pair, preventing the placement failures
that occurred with the previous approach.

## **Manual testing steps**

```gherkin
Feature: Perps Order Placement with USD as Source of Truth

  Scenario: User places a market order with precise USD amount
    Given user is on the Perps trading screen
    And user has sufficient balance

    When user enters "$100" USD amount via keypad
    And user selects "Market" order type
    And user taps "Place Order"

    Then order is placed with position size calculated from fresh market price
    And order execution succeeds without "insufficient margin" errors
    And no validation flickering occurs during input

  Scenario: User places order near minimum amount threshold
    Given user is on the Perps trading screen
    And market price causes calculated value to be near $10 minimum

    When user enters an amount that rounds to ~$9.99-$10.01
    And user places the order

    Then validation passes with 1% tolerance
    And no flickering validation errors appear

  Scenario: Price moves during order placement
    Given user has entered order details
    And calculated position size at price $50,000

    When market price moves to $50,500 (>1% move)
    And user places the order

    Then order is rejected with "Price moved too much" error
    And user is prompted to review and resubmit

  Scenario: User places limit order without price
    Given user is on the Perps trading screen
    And user selects "Limit" order type
    And user does not enter a limit price

    When user attempts to place order

    Then validation error displays "Price is required for limit orders"

  Scenario: User uses percentage buttons
    Given user is on the Perps trading screen
    And user has $1000 available balance

    When user taps "25%" button

    Then amount field shows "$250"
    And no optimization is triggered
    And position size is calculated correctly

  Scenario: User adjusts amount with slider
    Given user is on the Perps trading screen

    When user drags the amount slider

    Then amount updates in real-time
    And validation is skipped during interaction
    And validation applies after slider is released

  Scenario: User enters amount exceeding maximum
    Given user has $1000 available balance at 10x leverage
    And maximum possible order is $10,000

    When user enters "$15,000" via keypad
    And user dismisses the keypad

    Then amount is automatically clamped to "$10,000"
    And validation message explains the limit

  Scenario: User closes 100% of a position worth less than minimum
    Given user has an open position worth $5.23
    And minimum order size is $10

    When user taps "Close Position" button
    And selects "100%" (full close)
    And confirms the close

    Then position closes successfully
    And no minimum order size error appears
    And full position value is returned

  Scenario: User closes partial position below minimum
    Given user has an open position worth $100
    And minimum order size is $10

    When user attempts to close $8 worth of the position
    And confirms the close

    Then validation error displays "Minimum order size is $10"
    And close operation is prevented
```

## **Screenshots/Recordings**

### **Before**
- Orders occasionally failed with "insufficient margin" despite UI
showing valid amounts
- Validation messages flickered during input on low-priced tokens
- Complex optimization logic ran on every input change
- Position size calculated once in UI, potentially stale at execution

### **After**
- Consistent order execution with USD as source of truth
- No validation flickering with 1% tolerance on minimum amounts
- Simplified input handling without optimization overhead
- Position size recalculated with fresh price at execution time
- Price staleness validation prevents execution with stale prices

<!-- Add screenshots/recordings here if available -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.

---

## **Technical Notes for Reviewers**

### Critical Changes to Review

1. **Rounding Change in `calculatePositionSize`**
   - Changed from `Math.floor` to `Math.round`
   - Verify this doesn't cause issues with existing positions or orders
   - Check that rounding behavior matches exchange requirements

2. **Backward Compatibility**
   - `OrderParams.size` still present but recalculated by provider
   - Verify existing integrations continue to work
   - Test with and without `usdAmount` parameter

3. **Slippage Validation**
   - Price staleness check may reject valid orders in volatile markets
   - Default 1% tolerance (100 bps) - verify this is appropriate
   - Check error messages are clear to users

4. **Minimum Order Size Validation**
   - USD as source of truth - validates exact user input ($10 ≥ $10)
   - No tolerance needed when using usdAmount parameter
- **Full position closes (100%)** skip validation entirely via
`isFullClose` flag
   - **Partial position closes** enforce $10 minimum validation
   - **New positions** enforce $10 minimum validation
- Close position calculations use same USD validation logic as order
placement

5. **Input Clamping Logic**
   - Now only clamps for keypad input, not percentage/slider/max
   - Verify this doesn't break max amount validation
   - Test with various input methods

### Testing Recommendations

- Test with various token prices (low, medium, high)
- Test near minimum order size ($10) with price fluctuations
- Test with high leverage where rounding matters more
- Test order placement during price volatility
- Test limit orders with missing/invalid prices
- Verify no "insufficient margin" errors for valid amounts
- Check validation doesn't flicker during keypad input


[TAT-1902]:
https://consensyssoftware.atlassian.net/browse/TAT-1902?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Switches order/close flows to USD-as-source-of-truth with
provider-side size recalculation and unified slippage, improves
validation/precision, removes optimization logic, and updates
hooks/tests/docs.
> 
> - **Core trading/provider**:
> - Use USD as source of truth; provider recalculates size at execution
with fresh price and asset `szDecimals` (`HyperLiquidProvider.ts`).
> - Add slippage config via `ORDER_SLIPPAGE_CONFIG` (default 100 bps)
and price-staleness validation; pass `usdAmount`, `priceAtCalculation`,
`maxSlippageBps` through `OrderParams`.
> - Refactor order build/format helpers into `orderCalculations`
(`calculateFinalPositionSize`, `calculateOrderPriceAndSize`,
`buildOrdersArray`).
> - Support full-close bypass of $10 minimum via `isFullClose`;
propagate slippage params in close flows.
> - **Validation & precision**:
> - `calculatePositionSize`/close calculations use asset precision,
round to nearest, and ensure post-rounding USD meets target.
> - `validateOrder` now validates minimums from USD, requires price for
limit orders, and tolerates full closes.
> - Remove `findOptimalAmount`/related logic and old slippage from
`hyperLiquidConfig`.
> - **UI/hooks**:
> - `PerpsOrderView`/`PerpsClosePositionView`: pass USD + slippage
params; skip validation during input; clamp only for keypad; use market
data with fallback decimals.
> - `usePerpsMarketData` accepts `{ asset, showErrorToast }` and
auto-toasts on errors; expose loading.
> - `usePerpsOrderValidation`/`usePerpsClosePositionValidation`: add
`skipValidation`, use original USD for min checks.
> - **Types/constants**:
> - Extend `OrderParams`/`ClosePositionParams` with
USD/slippage/full-close fields; add
`DECIMAL_PRECISION_CONFIG.FALLBACK_SIZE_DECIMALS` and
`ORDER_SLIPPAGE_CONFIG`.
> - **Tests & docs**:
> - Update extensive tests to new params, rounding, and hook signatures;
adjust provider tests for price-required errors.
> - Refresh trading guide (market order/slippage sections) and fix
reference paths.
> - **Cleanup**:
> - Remove FinalizationRegistry polyfill from `shim.js`; simplify order
form by dropping optimization APIs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
fda1210. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: dylanbutler1 <99672693+dylanbutler1@users.noreply.github.com>
…22392)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

This PR aims to fix recipient input to show multiline for selected
address in send flow

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Fix recipient to be shown multi-line in send flow

## **Related issues**

Fixes: #22207

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<img width="568" height="1084" alt="Screenshot 2025-11-10 at 12 03 50"
src="https://github.com/user-attachments/assets/f8f0da96-2505-4c76-b77c-f904fcab3d6d"
/>


### **After**

<img width="568" height="1084" alt="Screenshot 2025-11-10 at 12 03 43"
src="https://github.com/user-attachments/assets/56c76b7c-a0c9-4640-9f02-bc3b446eed68"
/>


## **Pre-merge author checklist**

- [X] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I’ve included tests if applicable
- [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Replaces direct TextField props with a custom Input element to force
single-line recipient addresses and prevent multiline behavior.
> 
> - **Confirmations › RecipientInput
(`app/components/Views/confirmations/components/recipient-input/recipient-input.tsx`)**
> - Use `TextField` `inputElement` with `foundation/Input` to control
behavior.
> - Configure single-line input: `multiline={false}`,
`numberOfLines={1}`, `scrollEnabled={false}`,
`textAlignVertical="center"`, `textBreakStrategy="simple"`.
> - Move input props (value, change handlers,
autocorrect/spellcheck/autocomplete/capitalize, placeholder, autofocus,
testID) onto `Input`.
> - Apply `INPUT_STYLE_OVERRIDE` to remove height/lineHeight and pad
adjustments; disable state styles; set `textVariant` via
`TOKEN_TEXTFIELD_INPUT_TEXT_VARIANT`.
> - Keep start/end accessories (To label, Clear/Paste buttons)
unchanged.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e06f20c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

This PR aims to add PPOM validation requests for deeplinks.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: MetaMask/mobile-planning#2370
Fixes: #17358

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [X] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I’ve included tests if applicable
- [X] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] 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.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Integrates PPOM validation into deeplink transfer/approve flows,
generating a securityAlertId and passing it to addTransaction, with
refactors and tests.
> 
> - **Deeplink handling
(`app/components/Views/confirmations/utils/deeplink.ts`)**:
> - Add `validateWithPPOM` to build a PPOM request (with uuid-based
`securityAlertId`) and call `ppomUtil.validateRequest`.
> - Pass returned `securityAlertResponse` to `addTransaction` for both
native and ERC20 transfers.
> - Refactor tx construction to derive `txParams` and `transactionType`;
downgrade duplicate-request log from error to log.
> - **Approve flow
(`app/core/DeeplinkManager/TransactionManager/approveTransaction.ts`)**:
> - Compute `chainId`/`networkClientId`, call `validateWithPPOM`, and
include `securityAlertResponse` in `addTransaction`.
> - **Tests**:
> - Extend deeplink and approve tests to mock PPOM and UUID, assert PPOM
validation payload, `securityAlertResponse`, and `networkClientId`
wiring.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
daa4941. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Nov 12, 2025
@pull pull Bot added the ⤵️ pull label Nov 12, 2025
@pull pull Bot merged commit 86d1bd3 into Reality2byte:main Nov 12, 2025
6 of 37 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants