From 551dc585e3e0ecc83ce953908b9adafd0d6312b7 Mon Sep 17 00:00:00 2001 From: Julien Fontanel Date: Wed, 30 Sep 2026 18:16:50 +0200 Subject: [PATCH 1/2] feat(tron): use the shared EstimatedChanges UI component --- packages/tron-wallet-snap/CHANGELOG.md | 9 + packages/tron-wallet-snap/jest.config.js | 8 +- packages/tron-wallet-snap/snap.manifest.json | 2 +- .../EstimatedChanges.test.tsx | 95 ++++++++++ .../EstimatedChanges/EstimatedChanges.tsx | 168 +++--------------- .../ConfirmSignTransaction.tsx | 1 + .../ConfirmTransactionRequest.tsx | 1 + 7 files changed, 138 insertions(+), 146 deletions(-) create mode 100644 packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.test.tsx diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index 906a71deb..9950f1de6 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Render the confirmation "Estimated changes" section with the shared `EstimatedChanges` component from `@metamask/snap-networks-utils` ([#394](https://github.com/MetaMask/internal-snaps/pull/394)) + - Estimated changes from the previous scan now stay visible while a confirmation re-scans, instead of showing a loading skeleton + +### Fixed + +- Show "Estimated changes are not available" instead of "No estimated changes" when the transaction scan returns an error result, such as for a malformed transaction ([#394](https://github.com/MetaMask/internal-snaps/pull/394)) + ## [4.0.0] ### Added diff --git a/packages/tron-wallet-snap/jest.config.js b/packages/tron-wallet-snap/jest.config.js index 0fc594399..947d0368e 100644 --- a/packages/tron-wallet-snap/jest.config.js +++ b/packages/tron-wallet-snap/jest.config.js @@ -19,10 +19,10 @@ module.exports = { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 72.63, - functions: 79.95, - lines: 85.85, - statements: 85.86, + branches: 72.49, + functions: 79.91, + lines: 85.79, + statements: 85.79, }, }, }; diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index 6344cb7ac..770eb56b0 100644 --- a/packages/tron-wallet-snap/snap.manifest.json +++ b/packages/tron-wallet-snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/internal-snaps.git" }, "source": { - "shasum": "L4NZ35MXuCRWHzwx4paNtKwrBWApWCqwQZ0dpp9XeoI=", + "shasum": "1IlkNeNaW28YQoE0wK3OdDJctxoEBDqK6cxLQ0GyifY=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.test.tsx b/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.test.tsx new file mode 100644 index 000000000..c2de75528 --- /dev/null +++ b/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.test.tsx @@ -0,0 +1,95 @@ +import type { TransactionScanAssetChange } from '../../../../services/transaction-scan/types'; +import { FetchStatus } from '../../../../types/snap'; +import type { Preferences } from '../../../../types/snap'; +import { EstimatedChanges } from './EstimatedChanges'; + +const preferences = { locale: 'en', currency: 'usd' } as Preferences; + +const trxOut: TransactionScanAssetChange = { + type: 'out', + value: '10', + price: null, + symbol: 'TRX', + name: 'Tron', + logo: 'https://example.com/trx.png', + assetType: 'native', +}; + +const usdtIn: TransactionScanAssetChange = { + ...trxOut, + type: 'in', + value: '5', + symbol: 'USDT', + logo: null, +}; + +const render = ( + props: Partial[0]>, +): string => + JSON.stringify( + EstimatedChanges({ + changes: { assets: [trxOut, usdtIn] }, + scanStatus: 'SUCCESS', + preferences, + scanFetchStatus: FetchStatus.Fetched, + ...props, + }), + ); + +describe('EstimatedChanges', () => { + it('renders send and receive rows with translated labels', () => { + const serialized = render({}); + + expect(serialized).toContain('Estimated changes'); + expect(serialized).toContain('You send'); + expect(serialized).toContain('-10 TRX'); + expect(serialized).toContain('You receive'); + expect(serialized).toContain('+5 USDT'); + expect(serialized).toContain(trxOut.logo); + }); + + it.each([FetchStatus.Loading, FetchStatus.Fetching])( + 'renders a skeleton while %s and nothing is estimated yet', + (scanFetchStatus) => { + expect(render({ changes: null, scanFetchStatus })).toContain( + '"type":"Skeleton"', + ); + }, + ); + + it('keeps previously estimated rows visible while re-fetching', () => { + const serialized = render({ scanFetchStatus: FetchStatus.Fetching }); + + expect(serialized).toContain('-10 TRX'); + expect(serialized).not.toContain('"type":"Skeleton"'); + }); + + it('renders not available when the scan fetch fails', () => { + expect( + render({ changes: null, scanFetchStatus: FetchStatus.Error }), + ).toContain('Estimated changes are not available'); + }); + + it('renders not available when the scan result is an error', () => { + const serialized = render({ + changes: { assets: [] }, + scanStatus: 'ERROR', + }); + + expect(serialized).toContain('Estimated changes are not available'); + expect(serialized).not.toContain('No estimated changes'); + }); + + it('keeps estimated rows visible when the scan result is an error', () => { + const serialized = render({ scanStatus: 'ERROR' }); + + expect(serialized).toContain('-10 TRX'); + expect(serialized).not.toContain('Estimated changes are not available'); + }); + + it('renders no changes when fetched without assets', () => { + expect(render({ changes: { assets: [] } })).toContain( + 'No estimated changes', + ); + }); +}); diff --git a/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.tsx b/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.tsx index 524de89a8..475b65a2b 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/components/EstimatedChanges/EstimatedChanges.tsx @@ -1,15 +1,10 @@ +import { EstimatedChanges as SharedEstimatedChanges } from '@metamask/snap-networks-utils'; import type { ComponentOrElement } from '@metamask/snaps-sdk'; -import { - Box, - Section, - Text as SnapText, - Icon, - Tooltip, - Image, - Skeleton, -} from '@metamask/snaps-sdk/jsx'; -import type { TransactionScanEstimatedChanges } from '../../../../services/transaction-scan/types'; +import type { + TransactionScanEstimatedChanges, + TransactionScanStatus, +} from '../../../../services/transaction-scan/types'; import { FetchStatus } from '../../../../types/snap'; import type { Preferences } from '../../../../types/snap'; import { formatAmount } from '../../../../utils/formatAmount'; @@ -18,148 +13,39 @@ import { isFetchStatusLoadingOrFetching } from '../../../../utils/isFetchStatusL type EstimatedChangesProps = { changes: TransactionScanEstimatedChanges | null; + scanStatus: TransactionScanStatus | null; preferences: Preferences; scanFetchStatus: FetchStatus; }; -const EstimatedChangesSkeleton = ({ - preferences, -}: { - preferences: Preferences; -}): ComponentOrElement => { - const translate = i18n(preferences.locale); - - return ( -
- - - {translate('confirmation.estimatedChanges.title')} - - - - - - - - - -
- ); -}; - -const EstimatedChangesHeader = ({ - preferences, -}: { - preferences: Preferences; -}): ComponentOrElement => { - const translate = i18n(preferences.locale); - - return ( - - - {translate('confirmation.estimatedChanges.title')} - - - - - - ); -}; - -type AssetChangeProps = { - asset: TransactionScanEstimatedChanges['assets'][0]; -}; - -const AssetChange = ({ asset }: AssetChangeProps): ComponentOrElement => { - const formattedValue = formatAmount(asset.value); - const isOut = asset.type === 'out'; - - return ( - - {asset.logo ? ( - - - - ) : null} - - {isOut ? '-' : '+'} - {formattedValue} {asset.symbol} - - - ); -}; - export const EstimatedChanges = ({ changes, + scanStatus, preferences, scanFetchStatus, }: EstimatedChangesProps): ComponentOrElement => { const translate = i18n(preferences.locale); - // Keep "refreshing skeleton" for first loading + subsequent refreshes - const isFetching = isFetchStatusLoadingOrFetching(scanFetchStatus); - const isFetched = scanFetchStatus === FetchStatus.Fetched; - const isFetchError = scanFetchStatus === FetchStatus.Error; - - if (isFetching) { - return ; - } - - // API fetch error (network failure, etc.) - show "not available" - if (isFetchError) { - return ( -
- - - {translate('confirmation.estimatedChanges.notAvailable')} - -
- ); - } - - const send = changes?.assets.filter((asset) => asset.type === 'out') ?? []; - const receive = changes?.assets.filter((asset) => asset.type === 'in') ?? []; - - const hasChanges = send.length > 0 || receive.length > 0; - - if (isFetched && !hasChanges) { - return ( -
- - - {translate('confirmation.estimatedChanges.noChanges')} - -
- ); - } - return ( -
- - {send?.length > 0 ? ( - - - {translate('confirmation.estimatedChanges.send')} - - - {send?.map((asset) => ( - - ))} - - - ) : null} - {receive?.length > 0 ? ( - - - {translate('confirmation.estimatedChanges.receive')} - - - {receive?.map((asset) => ( - - ))} - - - ) : null} -
+ ({ + type: asset.type, + value: formatAmount(asset.value), + symbol: asset.symbol, + logo: asset.logo, + }))} + labels={{ + title: translate('confirmation.estimatedChanges.title'), + tooltip: translate('confirmation.estimatedChanges.tooltip'), + send: translate('confirmation.estimatedChanges.send'), + receive: translate('confirmation.estimatedChanges.receive'), + notAvailable: translate('confirmation.estimatedChanges.notAvailable'), + noChanges: translate('confirmation.estimatedChanges.noChanges'), + }} + isFetching={isFetchStatusLoadingOrFetching(scanFetchStatus)} + isUnavailable={ + scanFetchStatus === FetchStatus.Error || scanStatus === 'ERROR' + } + /> ); }; diff --git a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmSignTransaction/ConfirmSignTransaction.tsx b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmSignTransaction/ConfirmSignTransaction.tsx index 3dfccc742..f80d34e85 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmSignTransaction/ConfirmSignTransaction.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmSignTransaction/ConfirmSignTransaction.tsx @@ -87,6 +87,7 @@ export const ConfirmSignTransaction = ({ ); diff --git a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.tsx b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.tsx index 33dd8af5a..4d1f1353b 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.tsx @@ -78,6 +78,7 @@ export const ConfirmTransactionRequest = ({ ); From 384ceb3bd6432718bec9991c877474847f74d36e Mon Sep 17 00:00:00 2001 From: Julien Fontanel Date: Thu, 1 Oct 2026 10:44:36 +0200 Subject: [PATCH 2/2] chore: update changelog --- packages/tron-wallet-snap/CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index 9cefa3e1b..60a6fa302 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -9,13 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Render the confirmation "Estimated changes" section with the shared `EstimatedChanges` component from `@metamask/snap-networks-utils` ([#394](https://github.com/MetaMask/internal-snaps/pull/394)) +- Render the confirmation "Estimated changes" section with the shared `EstimatedChanges` component from `@metamask/snap-networks-utils` ([#396](https://github.com/MetaMask/internal-snaps/pull/396)) - Estimated changes from the previous scan now stay visible while a confirmation re-scans, instead of showing a loading skeleton ### Fixed -- Show "Estimated changes are not available" instead of "No estimated changes" when the transaction scan returns an error result, such as for a malformed transaction ([#394](https://github.com/MetaMask/internal-snaps/pull/394)) +- Show "Estimated changes are not available" instead of "No estimated changes" when the transaction scan returns an error result, such as for a malformed transaction ([#396](https://github.com/MetaMask/internal-snaps/pull/396)) - Report the MetaMask origin as lowercase `metamask` instead of `MetaMask` for MetaMask-initiated operations, so the origin matches the value used by the other non-EVM snaps and granted to the keyring methods, and so transaction scan requests are attributed to `https://metamask.io`. The confirmation UI keeps displaying `MetaMask`. ([#392](https://github.com/MetaMask/internal-snaps/pull/392)) +- Show "Estimated changes are not available" instead of "No estimated changes" when the transaction scan returns an error result, such as for a malformed transaction ([#396](https://github.com/MetaMask/internal-snaps/pull/396)) ## [4.0.0]