diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index 9eb0ce5e4..d6dc30f85 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Estimated changes from the previous scan now stay visible while a confirmation re-scans, instead of showing a loading skeleton - Render the confirmation security alert banner with the shared `TransactionAlert` component from `@metamask/snap-networks-utils` ([#414](https://github.com/MetaMask/internal-snaps/pull/414)) - A "Checking for security issues" banner is now shown while the transaction scan is in progress, instead of a loading skeleton +- Render the confirmation fee asset rows with the shared `Asset` component from `@metamask/snap-networks-utils` ([#429](https://github.com/MetaMask/internal-snaps/pull/429)) - `listAccountAssets` and `getAccountBalances` now fetch live assets and balances from the chain through the Snap's TronGrid clients instead of returning persisted state. ([#388](https://github.com/MetaMask/internal-snaps/pull/388)) ### Fixed diff --git a/packages/tron-wallet-snap/images/question-mark.svg b/packages/tron-wallet-snap/images/question-mark.svg deleted file mode 100644 index 8d2165746..000000000 --- a/packages/tron-wallet-snap/images/question-mark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/tron-wallet-snap/jest.config.js b/packages/tron-wallet-snap/jest.config.js index dfaaaeced..cebb2aa6e 100644 --- a/packages/tron-wallet-snap/jest.config.js +++ b/packages/tron-wallet-snap/jest.config.js @@ -5,10 +5,7 @@ module.exports = { preset: '@metamask/snaps-jest', transform: { '^.+\\.(t|j)sx?$': 'ts-jest', - }, - moduleNameMapper: { - ...baseConfig.moduleNameMapper, - '\\.svg$': 'jest-transform-stub', + '^.+\\.svg$': '/../../jest.svg-transformer.js', }, testMatch: ['**/src/**/?(*.)+(spec|test).[tj]s?(x)'], setupFilesAfterEnv: [ @@ -19,10 +16,10 @@ module.exports = { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 71.17, - functions: 80.95, - lines: 85.91, - statements: 85.9, + branches: 71.79, + functions: 81.56, + lines: 86.19, + statements: 86.18, }, }, }; diff --git a/packages/tron-wallet-snap/package.json b/packages/tron-wallet-snap/package.json index 032b031c1..938c02371 100644 --- a/packages/tron-wallet-snap/package.json +++ b/packages/tron-wallet-snap/package.json @@ -68,7 +68,6 @@ "ethers": "^6.15.0", "jest": "30.0.3", "jest-it-up": "^2.0.2", - "jest-transform-stub": "2.0.0", "lodash": "^4.17.21", "oxfmt": "^0.45.0", "tronweb": "patch:tronweb@npm%3A6.1.0#~/.yarn/patches/tronweb-npm-6.1.0-771b242b6a.patch", diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index 7fb609f4a..69f25e24d 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": "24Wu8vP5kufsOQxcQ8q8/FNuN/mDP/LFW7PxF98D3Uo=", + "shasum": "Ts+SpwPXHGuDCZNLn1PfTPwMX8ECWdp46bKrlYUr1vc=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/tron-wallet-snap/src/ui/confirmation/components/Asset/Asset.tsx b/packages/tron-wallet-snap/src/ui/confirmation/components/Asset/Asset.tsx deleted file mode 100644 index bbb84dc02..000000000 --- a/packages/tron-wallet-snap/src/ui/confirmation/components/Asset/Asset.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import type { CaipAssetType, ComponentOrElement } from '@metamask/snaps-sdk'; -import { - Box, - Icon, - Image, - Skeleton, - Text as SnapText, -} from '@metamask/snaps-sdk/jsx'; - -import questionMarkSvg from '../../../../../images/question-mark.svg'; -import { KnownCaip19Id } from '../../../../constants'; -import type { Preferences } from '../../../../types/snap'; -import { formatFiat } from '../../../../utils/formatFiat'; -import { tokenToFiat } from '../../../../utils/tokenToFiat'; - -type AssetProps = { - caipId: CaipAssetType; - symbol: string; - amount: string; - iconUrl?: string; - showAmount?: boolean; - price?: number | null; - preferences?: Preferences; - priceLoading?: boolean; -}; - -/** - * Asset component for displaying assets with optional icon, amount, and price. - * Pure component with no business logic - just visual display. - * - * @param props - The props for the asset component. - * @returns The rendered asset element. - */ -export const Asset = (props: AssetProps): ComponentOrElement => { - const { caipId, symbol, amount, iconUrl, price, preferences, priceLoading } = - props; - - const fiatValue = - preferences && price - ? formatFiat( - tokenToFiat(amount, price), - preferences.currency, - preferences.locale, - ) - : ''; - - const showPriceInfo = preferences !== undefined; - const showSkeleton = showPriceInfo && priceLoading; - const showFiat = showPriceInfo && !priceLoading && fiatValue; - - const isBandwidth = - caipId === KnownCaip19Id.BandwidthMainnet || - caipId === KnownCaip19Id.BandwidthNile || - caipId === KnownCaip19Id.BandwidthShasta; - - const isEnergy = - caipId === KnownCaip19Id.EnergyMainnet || - caipId === KnownCaip19Id.EnergyNile || - caipId === KnownCaip19Id.EnergyShasta; - - const isNormalAsset = !isBandwidth && !isEnergy; - const iconSrc = iconUrl ?? questionMarkSvg; - - return ( - - {showSkeleton ? : null} - {showFiat ? {fiatValue} : null} - - {isBandwidth ? : null} - {isEnergy ? : null} - {isNormalAsset ? ( - - ) : null} - - {`${amount} ${symbol}`} - - ); -}; diff --git a/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.test.tsx b/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.test.tsx new file mode 100644 index 000000000..255d207c0 --- /dev/null +++ b/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.test.tsx @@ -0,0 +1,97 @@ +import { FeeType } from '@metamask/keyring-api'; + +import { KnownCaip19Id } from '../../../constants'; +import type { ComputeFeeResult } from '../../../services/send/types'; +import { FetchStatus } from '../../../types/snap'; +import type { Preferences } from '../../../types/snap'; +import { formatFiat } from '../../../utils/formatFiat'; +import { tokenToFiat } from '../../../utils/tokenToFiat'; +import { Fees } from './Fees'; + +const preferences = { + locale: 'en', + currency: 'usd', +} as Preferences; + +const trxFee = { + type: FeeType.Base, + asset: { + unit: 'TRX', + type: KnownCaip19Id.TrxMainnet, + amount: '1.5', + fungible: true, + iconUrl: 'https://icon.example/trx.png', + }, +} as ComputeFeeResult[number]; + +const resourceFee = (unit: string, type: string): ComputeFeeResult[number] => + ({ + type: FeeType.Base, + asset: { unit, type, amount: '100', fungible: true }, + }) as ComputeFeeResult[number]; + +const tokenPrices = { + [KnownCaip19Id.TrxMainnet]: { price: 0.2 }, +} as never; + +const fiat = formatFiat(tokenToFiat('1.5', 0.2), 'usd', 'en'); + +describe('Fees', () => { + it('renders the fiat value before the TRX fee with its icon', () => { + const serialized = JSON.stringify( + Fees({ fees: [trxFee], preferences, tokenPrices }), + ); + + expect(serialized).toContain('"children":"1.5 TRX"'); + expect(serialized).toContain('"src":"https://icon.example/trx.png"'); + expect(serialized.indexOf(fiat)).toBeGreaterThan(-1); + expect(serialized.indexOf(fiat)).toBeLessThan( + serialized.indexOf('1.5 TRX'), + ); + }); + + it('renders a skeleton instead of the fiat value while prices load', () => { + const serialized = JSON.stringify( + Fees({ + fees: [trxFee], + preferences, + tokenPrices, + tokenPricesFetchStatus: FetchStatus.Fetching, + }), + ); + + expect(serialized).toContain('"type":"Skeleton"'); + expect(serialized).not.toContain(fiat); + }); + + it('renders only the fee when there is no price', () => { + const serialized = JSON.stringify(Fees({ fees: [trxFee], preferences })); + + expect(serialized).toContain('"children":"1.5 TRX"'); + expect(serialized).not.toContain(fiat); + expect(serialized).not.toContain('"type":"Skeleton"'); + }); + + it('renders resource fees with their icons after the TRX fee', () => { + const serialized = JSON.stringify( + Fees({ + fees: [ + resourceFee('ENERGY', KnownCaip19Id.EnergyMainnet), + resourceFee('BANDWIDTH', KnownCaip19Id.BandwidthNile), + trxFee, + ], + preferences, + }), + ); + + expect(serialized).toContain('"name":"flash"'); + expect(serialized).toContain('"name":"connect"'); + expect(serialized.indexOf('1.5 TRX')).toBeLessThan( + serialized.indexOf('100 ENERGY'), + ); + expect(serialized.indexOf('100 ENERGY')).toBeLessThan( + serialized.indexOf('100 BANDWIDTH'), + ); + expect(serialized.match(/"type":"Image"/gu)).toHaveLength(1); + }); +}); diff --git a/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.tsx b/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.tsx index 027a116ab..fd917646b 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/components/Fees.tsx @@ -1,13 +1,26 @@ +import { Asset } from '@metamask/snap-networks-utils'; import type { ComponentOrElement } from '@metamask/snaps-sdk'; import { Box, Text as SnapText } from '@metamask/snaps-sdk/jsx'; +import type { IconProps } from '@metamask/snaps-sdk/jsx'; import type { SpotPrices } from '../../../clients/price-api/types'; +import { KnownCaip19Id } from '../../../constants'; import type { ComputeFeeResult } from '../../../services/send/types'; import { FetchStatus } from '../../../types/snap'; import type { Preferences } from '../../../types/snap'; +import { formatFiat } from '../../../utils/formatFiat'; import { i18n } from '../../../utils/i18n'; import { isFetchStatusLoadingOrFetching } from '../../../utils/isFetchStatusLoadingOrFetching'; -import { Asset } from './Asset/Asset'; +import { tokenToFiat } from '../../../utils/tokenToFiat'; + +const RESOURCE_ICONS: Partial> = { + [KnownCaip19Id.BandwidthMainnet]: 'connect', + [KnownCaip19Id.BandwidthNile]: 'connect', + [KnownCaip19Id.BandwidthShasta]: 'connect', + [KnownCaip19Id.EnergyMainnet]: 'flash', + [KnownCaip19Id.EnergyNile]: 'flash', + [KnownCaip19Id.EnergyShasta]: 'flash', +}; type FeesProps = { fees: ComputeFeeResult; @@ -68,13 +81,20 @@ export const Fees = ({ {/* Right side - fee value with asset display including price */} ); diff --git a/yarn.lock b/yarn.lock index b56ebc580..fa50b1418 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3944,7 +3944,6 @@ __metadata: ethers: "npm:^6.15.0" jest: "npm:30.0.3" jest-it-up: "npm:^2.0.2" - jest-transform-stub: "npm:2.0.0" lodash: "npm:^4.17.21" oxfmt: "npm:^0.45.0" tronweb: "patch:tronweb@npm%3A6.1.0#~/.yarn/patches/tronweb-npm-6.1.0-771b242b6a.patch"