From 7c60d780fdf2cd4119a5c987257596eca9897aac Mon Sep 17 00:00:00 2001 From: Alejandro Garcia Anglada Date: Mon, 20 Apr 2026 16:02:37 +0000 Subject: [PATCH] release(runway): cherry-pick fix(perps): percent issue on markets page cp-13.28.0 (#41941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The 24h percentage change on the perps markets list was sometimes displayed without the `%` suffix. This happened because the WebSocket live-price stream can emit `percentChange24h` values without a trailing `%` (e.g. `+2.84` instead of `+2.84%`). `usePerpsLiveMarketListData` merges that value directly into `market.change24hPercent` with no normalization, and `MarketRow` was rendering the raw string. The detail page and market cards already guard against this using `formatChangePercent` / `formatSignedChangePercent` from `utils.ts`. This fix applies the same `formatSignedChangePercent` normalization inside `MarketRow` — both for the right-side change column and for the secondary `priceChange` metric display — so the `%` symbol is always present regardless of whether the value came from REST or WebSocket. ## **Changelog** CHANGELOG entry: Fixed a bug where the 24h percentage change on the perps markets page was sometimes displayed without the `%` symbol. ## **Related issues** Fixes: ## **Manual testing steps** 1. Open the MetaMask extension and navigate to the Perps section. 2. Open the Markets list page. 3. Observe the 24h change column — all values should display with a `%` suffix (e.g. `+2.84%`, `-1.23%`). 4. Wait for the WebSocket live-price stream to push updates and confirm the `%` remains present after a live update. ## **Screenshots/Recordings** ### **Before** ### **After** Screenshot 2026-04-20 at 13 43 56 ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/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-extension/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. --- > [!NOTE] > **Low Risk** > Low risk UI formatting change that only normalizes the `change24hPercent` string; limited to display logic plus a small test addition. > > **Overview** > Ensures the perps markets list always shows a properly formatted 24h change percent by routing `market.change24hPercent` through `formatSignedChangePercent` (adds missing `%` and normalizes sign) in `MarketRow`, including the secondary `priceChange` metric. > > Adds a regression test covering the live-stream case where the percent value arrives without a trailing `%`. > > Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit b4e78565b220ec203a914ed2f5ab7e1e9d453722. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot). --- .../market-list/components/market-row/market-row.test.tsx | 7 +++++++ .../perps/market-list/components/market-row/market-row.tsx | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ui/pages/perps/market-list/components/market-row/market-row.test.tsx b/ui/pages/perps/market-list/components/market-row/market-row.test.tsx index 9146e28462df..befd45cd34c0 100644 --- a/ui/pages/perps/market-list/components/market-row/market-row.test.tsx +++ b/ui/pages/perps/market-list/components/market-row/market-row.test.tsx @@ -65,6 +65,13 @@ describe('MarketRow', () => { expect(screen.getByText('+2.5%')).toBeInTheDocument(); }); + it('appends % to change24hPercent when stream omits it', () => { + const market = createMockMarket({ change24hPercent: '+2.5' }); + renderWithProvider(, mockStore); + + expect(screen.getByText('+2.5%')).toBeInTheDocument(); + }); + it('displays the max leverage', () => { renderWithProvider(, mockStore); diff --git a/ui/pages/perps/market-list/components/market-row/market-row.tsx b/ui/pages/perps/market-list/components/market-row/market-row.tsx index dea5786a99b5..0a816390bdf8 100644 --- a/ui/pages/perps/market-list/components/market-row/market-row.tsx +++ b/ui/pages/perps/market-list/components/market-row/market-row.tsx @@ -13,6 +13,7 @@ import { PerpsTokenLogo } from '../../../../../components/app/perps/perps-token- import { getDisplaySymbol, getChangeColor, + formatSignedChangePercent, } from '../../../../../components/app/perps/utils'; import { useFormatters } from '../../../../../hooks/useFormatters'; import type { PerpsMarketData } from '../../../../../components/app/perps/types'; @@ -44,7 +45,7 @@ const getMetricValue = ( case 'volume': return `${market.volume} Vol`; case 'priceChange': - return market.change24hPercent; + return formatSignedChangePercent(market.change24hPercent); case 'fundingRate': if (market.fundingRate === undefined) { return 'N/A'; @@ -153,7 +154,7 @@ export const MarketRow: React.FC = ({ {market.price} - {market.change24hPercent} + {formatSignedChangePercent(market.change24hPercent)}