From 9427f7e9b0d411361e8070e6995b043c711e9881 Mon Sep 17 00:00:00 2001 From: Frederic HENG Date: Wed, 30 Sep 2026 16:23:51 +0200 Subject: [PATCH 1/5] fix(tron): report the MetaMask origin as lowercase MetaMask-initiated operations reported their origin as `MetaMask`, while the keyring methods are granted to `metamask` and the other non-EVM snaps use the lowercase value. Because `TransactionScanService` only maps `metamask` to `https://metamask.io`, Tron transaction scan requests were sent with the literal `MetaMask` origin instead. - Add a `METAMASK_ORIGIN` constant and use it for every MetaMask-initiated origin (unified send, confirmations, submitted/finalized tracking). - Reuse the constant in `TransactionScanService` so the normalization applies. - Keep displaying `MetaMask` in the confirmation UI via `formatOrigin`. --- packages/tron-wallet-snap/CHANGELOG.md | 4 ++ packages/tron-wallet-snap/snap.manifest.json | 2 +- .../tron-wallet-snap/src/constants/index.ts | 8 +++ .../clientRequest/clientRequest.test.ts | 3 +- .../handlers/clientRequest/clientRequest.ts | 15 +++-- .../src/handlers/cronjob/cronjob.test.tsx | 5 +- .../src/handlers/cronjob/cronjob.tsx | 8 ++- .../confirmation/ConfirmationHandler.test.ts | 16 +++-- .../confirmation/ConfirmationHandler.ts | 4 +- .../src/services/send/SendService.test.ts | 3 +- .../src/services/send/SendService.ts | 9 ++- .../TransactionScanService.test.ts | 59 ++++++++++++++++++- .../TransactionScanService.ts | 2 +- .../ConfirmTransactionRequest.test.tsx | 4 +- .../ConfirmTransactionRequest.tsx | 3 +- .../ConfirmTransactionRequest/render.test.tsx | 6 +- .../ConfirmTransactionRequest/render.tsx | 4 +- 17 files changed, 123 insertions(+), 32 deletions(-) diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index 906a71deb..862bb8431 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Report the MetaMask origin as lowercase `metamask` instead of `MetaMask` for MetaMask-initiated operations, so transaction scan requests are correctly attributed to `https://metamask.io` and the origin matches the value used by the other non-EVM snaps and granted to the keyring methods. The confirmation UI keeps displaying `MetaMask`. + ## [4.0.0] ### Added diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index 6344cb7ac..f4ae41723 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": "1NIlNEovur3nxZIh1gjq4sxiBQIMya6sfp+U3/XVjMw=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/tron-wallet-snap/src/constants/index.ts b/packages/tron-wallet-snap/src/constants/index.ts index c7d762c47..b288f05be 100644 --- a/packages/tron-wallet-snap/src/constants/index.ts +++ b/packages/tron-wallet-snap/src/constants/index.ts @@ -1,6 +1,14 @@ import { BigNumber } from 'bignumber.js'; export const ZERO = BigNumber(0); + +/** + * Origin used for operations initiated by MetaMask itself (unified send, + * background tracking), as opposed to a dApp origin. Must stay lowercase to + * match the origin granted to the keyring methods and the other non-EVM snaps. + */ +export const METAMASK_ORIGIN = 'metamask'; + export const ACCOUNT_ACTIVATION_FEE_TRX = BigNumber(1); export const MEMO_FEE_TRX = BigNumber(1); export const SUN_IN_TRX = 1_000_000; diff --git a/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.test.ts b/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.test.ts index f127ca69c..78051532f 100644 --- a/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.test.ts +++ b/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.test.ts @@ -14,6 +14,7 @@ import type { TronWebFactory } from '../../clients/tronweb/TronWebFactory'; import { FALLBACK_FEE, FEE_LIMIT, + METAMASK_ORIGIN, Network, Networks, TRACK_TX_INTERVAL, @@ -1962,7 +1963,7 @@ describe('ClientRequestHandler - signAndSendTransaction', () => { expect(mockAnalyticsService.trackTransactionSubmitted).toHaveBeenCalledWith( { - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: 'tron:eoa', chainIdCaip: scope, }, diff --git a/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.ts b/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.ts index 6a854c702..0edce2161 100644 --- a/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.ts +++ b/packages/tron-wallet-snap/src/handlers/clientRequest/clientRequest.ts @@ -26,6 +26,7 @@ import type { TronWebFactory } from '../../clients/tronweb/TronWebFactory'; import { FALLBACK_FEE, FEE_LIMIT, + METAMASK_ORIGIN, Network, Networks, TRACK_TX_INTERVAL, @@ -411,12 +412,13 @@ export class ClientRequestHandler { await this.#transactionsService.save(pendingTransaction); /** - * Origin is 'MetaMask' because client requests come from MetaMask's own - * unified send flow, matching the unified send path and the background - * transaction tracker. + * Client requests come from MetaMask's own unified send flow, matching the + * unified send path and the background transaction tracker. The origin is + * lowercased so it is recognized as MetaMask by the security alerts scan + * and stays consistent with the other non-EVM snaps. */ await this.#analyticsService.trackTransactionSubmitted({ - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: account.type, chainIdCaip: scope, }); @@ -692,7 +694,8 @@ export class ClientRequestHandler { /** * Show the confirmation UI. - * Origin is 'MetaMask' because client requests come from MetaMask's own unified send flow. + * Client requests come from MetaMask's own unified send flow, so the origin + * is reported as MetaMask. */ const confirmed = await this.#confirmationHandler.confirmTransactionRequest( { @@ -703,7 +706,7 @@ export class ClientRequestHandler { fees, asset, accountType: account.type, - origin: 'MetaMask', + origin: METAMASK_ORIGIN, transactionRawData: freshTransactionRawData, }, ); diff --git a/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.test.tsx b/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.test.tsx index 63c00b898..77f5c1b6f 100644 --- a/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.test.tsx +++ b/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.test.tsx @@ -8,6 +8,7 @@ import type { SnapClient } from '../../clients/snap/SnapClient'; import type { TronHttpClient } from '../../clients/tron-http/TronHttpClient'; import type { TronWebFactory } from '../../clients/tronweb/TronWebFactory'; import { + METAMASK_ORIGIN, Network, TRACK_TX_INTERVAL, TRACK_TX_MAX_ATTEMPTS, @@ -138,7 +139,7 @@ function buildMockInterfaceContext( overrides: Partial = {}, ): ConfirmTransactionRequestContext { return { - origin: 'MetaMask', + origin: METAMASK_ORIGIN, scope: Network.Mainnet, fromAddress: 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8', toAddress: 'TQkE4s6hQqxym4fYvtVLNEGPsaAChFqxPk', @@ -1029,7 +1030,7 @@ describe('CronHandler', () => { expect( mockAnalyticsService.trackTransactionFinalized, ).toHaveBeenCalledWith({ - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: mockAccount.type, chainIdCaip: Network.Mainnet, }); diff --git a/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.tsx b/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.tsx index c3db35894..e1385f280 100644 --- a/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.tsx +++ b/packages/tron-wallet-snap/src/handlers/cronjob/cronjob.tsx @@ -10,7 +10,11 @@ import type { PriceApiClient } from '../../clients/price-api/PriceApiClient'; import type { SnapClient } from '../../clients/snap/SnapClient'; import type { TronHttpClient } from '../../clients/tron-http/TronHttpClient'; import type { Network } from '../../constants'; -import { TRACK_TX_INTERVAL, TRACK_TX_MAX_ATTEMPTS } from '../../constants'; +import { + METAMASK_ORIGIN, + TRACK_TX_INTERVAL, + TRACK_TX_MAX_ATTEMPTS, +} from '../../constants'; import type { AccountsService } from '../../services/accounts/AccountsService'; import type { UnencryptedStateValue } from '../../services/state/stateTypes'; import type { TransactionExpirationRefresherService } from '../../services/transaction-expiration-refresher/TransactionExpirationRefresherService'; @@ -735,7 +739,7 @@ export class CronHandler { // Track Transaction Finalized event now that transaction is confirmed await this.#analyticsService.trackTransactionFinalized({ - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: senderAccount.type, chainIdCaip: scope, }); diff --git a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts index bc481d721..efac829d9 100644 --- a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts +++ b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts @@ -7,7 +7,13 @@ import { BigNumber } from 'bignumber.js'; import type { SnapClient } from '../../clients/snap/SnapClient'; import type { TronWebFactory } from '../../clients/tronweb/TronWebFactory'; -import { KnownCaip19Id, Network, Networks, ZERO } from '../../constants'; +import { + KnownCaip19Id, + METAMASK_ORIGIN, + Network, + Networks, + ZERO, +} from '../../constants'; import type { AssetEntity, ResourceAsset } from '../../entities/assets'; import { TronMultichainMethod } from '../../handlers/keyring/keyring-types'; import { getIconUrlForKnownAsset } from '../../ui/confirmation/utils/getIconUrlForKnownAsset'; @@ -420,7 +426,7 @@ describe('ConfirmationHandler', () => { fees: defaultFees, asset: mockAsset, accountType: 'tron:eoa', - origin: 'MetaMask', + origin: METAMASK_ORIGIN, transactionRawData: mockTransactionRawData, }; @@ -433,7 +439,7 @@ describe('ConfirmationHandler', () => { expect(result).toBe(true); expect(mockAnalyticsService.trackTransactionAdded).toHaveBeenCalledWith( { - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: 'tron:eoa', chainIdCaip: Network.Mainnet, }, @@ -441,7 +447,7 @@ describe('ConfirmationHandler', () => { expect( mockAnalyticsService.trackTransactionApproved, ).toHaveBeenCalledWith({ - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: 'tron:eoa', chainIdCaip: Network.Mainnet, }); @@ -461,7 +467,7 @@ describe('ConfirmationHandler', () => { expect( mockAnalyticsService.trackTransactionRejected, ).toHaveBeenCalledWith({ - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: 'tron:eoa', chainIdCaip: Network.Mainnet, }); diff --git a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts index f81d545c4..f1393f6f2 100644 --- a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts +++ b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts @@ -11,7 +11,7 @@ import type { Types as TronwebTypes } from 'tronweb'; import type { SnapClient } from '../../clients/snap/SnapClient'; import type { TronWebFactory } from '../../clients/tronweb/TronWebFactory'; -import { Networks, ZERO } from '../../constants'; +import { Networks, METAMASK_ORIGIN, ZERO } from '../../constants'; import type { Network } from '../../constants'; import type { AssetEntity } from '../../entities/assets'; import { TronMultichainMethod } from '../../handlers/keyring/keyring-types'; @@ -289,7 +289,7 @@ export class ConfirmationHandler { scope, account, transaction: { rawDataHex: '', type: '' }, - origin: 'MetaMask', + origin: METAMASK_ORIGIN, preferences, networkImage: TRX_IMAGE_SVG, scan: null, diff --git a/packages/tron-wallet-snap/src/services/send/SendService.test.ts b/packages/tron-wallet-snap/src/services/send/SendService.test.ts index c4c248259..dc815d8b8 100644 --- a/packages/tron-wallet-snap/src/services/send/SendService.test.ts +++ b/packages/tron-wallet-snap/src/services/send/SendService.test.ts @@ -7,6 +7,7 @@ import type { Types as TronwebTypes } from 'tronweb'; import { FEE_LIMIT, + METAMASK_ORIGIN, Network, Networks, TRACK_TX_INTERVAL, @@ -164,7 +165,7 @@ describe('SendService', () => { expect( mockAnalyticsService.trackTransactionSubmitted, ).toHaveBeenCalledWith({ - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: 'tron:eoa', chainIdCaip: Network.Mainnet, }); diff --git a/packages/tron-wallet-snap/src/services/send/SendService.ts b/packages/tron-wallet-snap/src/services/send/SendService.ts index 3f9725951..eae3ea60d 100644 --- a/packages/tron-wallet-snap/src/services/send/SendService.ts +++ b/packages/tron-wallet-snap/src/services/send/SendService.ts @@ -6,7 +6,12 @@ import type { TronWeb, Types as TronwebTypes } from 'tronweb'; import type { SnapClient } from '../../clients/snap/SnapClient'; import type { TronWebFactory } from '../../clients/tronweb/TronWebFactory'; import type { Network } from '../../constants'; -import { Networks, TRACK_TX_INTERVAL, ZERO } from '../../constants'; +import { + METAMASK_ORIGIN, + Networks, + TRACK_TX_INTERVAL, + ZERO, +} from '../../constants'; import type { AssetEntity } from '../../entities/assets'; import { SendErrorCodes } from '../../handlers/clientRequest/types'; import { BackgroundEventMethod } from '../../handlers/cronjob/cronjob'; @@ -382,7 +387,7 @@ export class SendService { scope, fromAccountId, transaction, - origin = 'MetaMask', + origin = METAMASK_ORIGIN, }: { scope: Network; fromAccountId: string; diff --git a/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts b/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts index 52ec63cde..39aa3dbd8 100644 --- a/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts +++ b/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts @@ -7,7 +7,7 @@ import { Types as TronwebTypes } from 'tronweb'; import { SecurityAlertsApiClient } from '../../clients/security-alerts-api/SecurityAlertsApiClient'; import type { SecurityAlertSimulationValidationResponse } from '../../clients/security-alerts-api/structs'; import type { SnapClient } from '../../clients/snap/SnapClient'; -import { Network } from '../../constants'; +import { METAMASK_ORIGIN, Network } from '../../constants'; import { mockLogger } from '../../utils/mockLogger'; import { TransactionScanService } from './TransactionScanService'; import type { TransactionScanResult } from './types'; @@ -820,4 +820,61 @@ describe('TransactionScanService', () => { }); }); }); + + describe('origin normalization', () => { + const createService = (): { + service: TransactionScanService; + mockSecurityAlertsApiClient: jest.Mocked< + Pick + >; + } => { + const mockSecurityAlertsApiClient = createMockSecurityAlertsApiClient({ + simulation: { status: 'Success' }, + validation: { status: 'Success', result_type: 'Benign' }, + }); + const mockSnapClient = createMockSnapClient(); + const service = new TransactionScanService( + mockSecurityAlertsApiClient as unknown as SecurityAlertsApiClient, + mockSnapClient as unknown as SnapClient, + mockLogger, + mockAnalyticsService, + ); + + return { service, mockSecurityAlertsApiClient }; + }; + + it('resolves the MetaMask origin to its URL for the scan', async () => { + const { service, mockSecurityAlertsApiClient } = createService(); + + await service.scanTransaction({ + accountAddress: mockAccount.address, + transactionRawData: createWellFormedTransactionRawData(), + origin: METAMASK_ORIGIN, + scope: Network.Mainnet, + }); + + expect( + mockSecurityAlertsApiClient.scanTransaction, + ).toHaveBeenCalledWith( + expect.objectContaining({ origin: 'https://metamask.io' }), + ); + }); + + it('leaves dApp origins untouched for the scan', async () => { + const { service, mockSecurityAlertsApiClient } = createService(); + + await service.scanTransaction({ + accountAddress: mockAccount.address, + transactionRawData: createWellFormedTransactionRawData(), + origin: 'https://example.com', + scope: Network.Mainnet, + }); + + expect( + mockSecurityAlertsApiClient.scanTransaction, + ).toHaveBeenCalledWith( + expect.objectContaining({ origin: 'https://example.com' }), + ); + }); + }); }); diff --git a/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.ts b/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.ts index 9b77f1bd7..ecb2211ef 100644 --- a/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.ts +++ b/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.ts @@ -14,6 +14,7 @@ import type { } from '../../clients/security-alerts-api/structs'; import type { SnapClient } from '../../clients/snap/SnapClient'; import type { Network } from '../../constants'; +import { METAMASK_ORIGIN } from '../../constants'; import { isTransactionWellFormed } from '../../validation/transaction'; import type { TransactionScanAssetChange, @@ -23,7 +24,6 @@ import type { } from './types'; import { ScanStatus, SecurityAlertResponse, SimulationStatus } from './types'; -const METAMASK_ORIGIN = 'metamask'; const METAMASK_ORIGIN_URL = 'https://metamask.io'; export class TransactionScanService { diff --git a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx index 492e30568..a63b68424 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx @@ -1,4 +1,4 @@ -import { Network } from '../../../../constants'; +import { METAMASK_ORIGIN, Network } from '../../../../constants'; import { SimulationStatus } from '../../../../services/transaction-scan/types'; import type { TransactionScanResult } from '../../../../services/transaction-scan/types'; import { FetchStatus } from '../../../../types/snap'; @@ -55,7 +55,7 @@ describe('ConfirmTransactionRequest', () => { }; const baseContext: ConfirmTransactionRequestContext = { - origin: 'MetaMask', + origin: METAMASK_ORIGIN, scope: Network.Mainnet, fromAddress: 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8', toAddress: 'TQkE4s6hQqxym4fYvtVLNEGPsaAChFqxPk', 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..c706ceb21 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 @@ -19,6 +19,7 @@ import { SimulationStatus } from '../../../../services/transaction-scan/types'; import { TRX_IMAGE_SVG } from '../../../../static/tron-logo'; import { FetchStatus } from '../../../../types/snap'; import { getExplorerUrl } from '../../../../utils/getExplorerUrl'; +import { formatOrigin } from '../../../../utils/formatOrigin'; import { i18n } from '../../../../utils/i18n'; import { EstimatedChanges } from '../../components/EstimatedChanges/EstimatedChanges'; import { Fees } from '../../components/Fees'; @@ -121,7 +122,7 @@ export const ConfirmTransactionRequest = ({ - {origin} + {formatOrigin(origin)} {null} {/* From */} diff --git a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.test.tsx b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.test.tsx index 462d78e11..49b4ef249 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.test.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.test.tsx @@ -6,7 +6,7 @@ import { extractScanParametersFromTransactionData, } from '../../../../clients/security-alerts-api/utils'; import type { SnapClient } from '../../../../clients/snap/SnapClient'; -import { Network } from '../../../../constants'; +import { METAMASK_ORIGIN, Network } from '../../../../constants'; import type { AssetEntity } from '../../../../entities/assets'; import { BackgroundEventMethod } from '../../../../handlers/cronjob/cronjob'; import type { UnencryptedStateValue } from '../../../../services/state/stateTypes'; @@ -127,7 +127,7 @@ const defaultIncomingContext = { amount: '1', fees: [] as never[], asset: mockAsset, - origin: 'MetaMask', + origin: METAMASK_ORIGIN, accountType: 'tron:eoa', transactionRawData: defaultTransactionRawData, }; @@ -259,7 +259,7 @@ describe('ConfirmTransactionRequest render', () => { expect.objectContaining({ accountAddress: 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8', transactionRawData: expect.any(Object), - origin: 'MetaMask', + origin: METAMASK_ORIGIN, scope: Network.Mainnet, options: ['simulation', 'validation'], }), diff --git a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.tsx b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.tsx index d307fdcb0..34a84ae63 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/render.tsx @@ -6,7 +6,7 @@ import type { DialogResult, Json } from '@metamask/snaps-sdk'; import type { Types as TronwebTypes } from 'tronweb'; import type { SnapClient } from '../../../../clients/snap/SnapClient'; -import { Network } from '../../../../constants'; +import { METAMASK_ORIGIN, Network } from '../../../../constants'; import snapContext from '../../../../context'; import type { AssetEntity } from '../../../../entities/assets'; import { BackgroundEventMethod } from '../../../../handlers/cronjob/cronjob'; @@ -35,7 +35,7 @@ export const DEFAULT_CONFIRMATION_CONTEXT: ConfirmTransactionRequestContext = { uiAmount: '0', iconUrl: '', }, - origin: 'MetaMask', + origin: METAMASK_ORIGIN, networkImage: TRX_IMAGE_SVG, tokenPrices: {}, tokenPricesFetchStatus: FetchStatus.Initial, From 5669b4634d254169d4ea5e75d5c058f4c39e8edd Mon Sep 17 00:00:00 2001 From: Frederic HENG Date: Wed, 30 Sep 2026 16:36:13 +0200 Subject: [PATCH 2/5] chore(tron): update CHANGELOG.md --- packages/tron-wallet-snap/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index 862bb8431..fd6cba5da 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Report the MetaMask origin as lowercase `metamask` instead of `MetaMask` for MetaMask-initiated operations, so transaction scan requests are correctly attributed to `https://metamask.io` and the origin matches the value used by the other non-EVM snaps and granted to the keyring methods. The confirmation UI keeps displaying `MetaMask`. +- 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. ([#392](https://github.com/MetaMask/internal-snaps/pull/392)) ## [4.0.0] From 7858ca883f34c734c1ac3179155982373ca2d2ea Mon Sep 17 00:00:00 2001 From: Frederic HENG Date: Wed, 30 Sep 2026 16:52:55 +0200 Subject: [PATCH 3/5] style(tron): apply oxfmt formatting Reformat the files touched by the previous commit so `yarn lint:misc:check` passes: reorder the `formatOrigin` import and unwrap two `expect` calls. --- .../transaction-scan/TransactionScanService.test.ts | 8 ++------ .../ConfirmTransactionRequest.tsx | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts b/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts index 39aa3dbd8..7264128ca 100644 --- a/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts +++ b/packages/tron-wallet-snap/src/services/transaction-scan/TransactionScanService.test.ts @@ -853,9 +853,7 @@ describe('TransactionScanService', () => { scope: Network.Mainnet, }); - expect( - mockSecurityAlertsApiClient.scanTransaction, - ).toHaveBeenCalledWith( + expect(mockSecurityAlertsApiClient.scanTransaction).toHaveBeenCalledWith( expect.objectContaining({ origin: 'https://metamask.io' }), ); }); @@ -870,9 +868,7 @@ describe('TransactionScanService', () => { scope: Network.Mainnet, }); - expect( - mockSecurityAlertsApiClient.scanTransaction, - ).toHaveBeenCalledWith( + expect(mockSecurityAlertsApiClient.scanTransaction).toHaveBeenCalledWith( expect.objectContaining({ origin: 'https://example.com' }), ); }); 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 c706ceb21..9d3076923 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 @@ -18,8 +18,8 @@ import { Networks } from '../../../../constants'; import { SimulationStatus } from '../../../../services/transaction-scan/types'; import { TRX_IMAGE_SVG } from '../../../../static/tron-logo'; import { FetchStatus } from '../../../../types/snap'; -import { getExplorerUrl } from '../../../../utils/getExplorerUrl'; import { formatOrigin } from '../../../../utils/formatOrigin'; +import { getExplorerUrl } from '../../../../utils/getExplorerUrl'; import { i18n } from '../../../../utils/i18n'; import { EstimatedChanges } from '../../components/EstimatedChanges/EstimatedChanges'; import { Fees } from '../../components/Fees'; From 757ad9ecc00670cefe716423780efbcb4a10b639 Mon Sep 17 00:00:00 2001 From: Frederic HENG Date: Wed, 30 Sep 2026 17:36:39 +0200 Subject: [PATCH 4/5] fix(tron): keep the raw origin for the security scan `confirmTransactionRequest` formatted the origin before handing it to the confirmation view, and the view passes the stored origin straight to the transaction scan. The scan normalizes only the lowercase `metamask` to `https://metamask.io`, so every MetaMask-initiated scan was sent the literal `MetaMask` and never resolved to the MetaMask URL, both on the initial scan and on each background refresh. Keep the raw origin in the interface context and format it only at the display leaf, matching `ConfirmSignTransaction` and `ConfirmSignMessage`. `ConfirmTransactionRequest` already renders `formatOrigin(origin)`, so the user-facing label is unchanged. --- packages/tron-wallet-snap/CHANGELOG.md | 2 +- packages/tron-wallet-snap/snap.manifest.json | 2 +- .../confirmation/ConfirmationHandler.test.ts | 23 +++++++++++++++++-- .../confirmation/ConfirmationHandler.ts | 8 +++++-- .../ConfirmTransactionRequest.test.tsx | 23 +++++++++++++++++++ 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/packages/tron-wallet-snap/CHANGELOG.md b/packages/tron-wallet-snap/CHANGELOG.md index fd6cba5da..78ed7a86b 100644 --- a/packages/tron-wallet-snap/CHANGELOG.md +++ b/packages/tron-wallet-snap/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- 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. ([#392](https://github.com/MetaMask/internal-snaps/pull/392)) +- 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)) ## [4.0.0] diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index f4ae41723..4768d2277 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": "1NIlNEovur3nxZIh1gjq4sxiBQIMya6sfp+U3/XVjMw=", + "shasum": "w8+KXIrSQt4Klqgnc69CyflhR6PUUiZRgoOx84JriXQ=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts index efac829d9..7415b4237 100644 --- a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts +++ b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.test.ts @@ -477,7 +477,7 @@ describe('ConfirmationHandler', () => { }); }); - it('passes formatted origin and transactionRawData to render', async () => { + it('passes the raw origin and transactionRawData to render', async () => { await withConfirmationHandler( async ({ handler, mockSnapClient, mockState }) => { mockRenderConfirmTransactionRequest.mockResolvedValue(true); @@ -491,7 +491,7 @@ describe('ConfirmationHandler', () => { mockSnapClient, mockState, expect.objectContaining({ - origin: 'example.com', + origin: 'https://example.com', transactionRawData: mockTransactionRawData, }), ); @@ -499,6 +499,25 @@ describe('ConfirmationHandler', () => { ); }); + it('passes the raw MetaMask origin to render so the scan can recognize it', async () => { + await withConfirmationHandler( + async ({ handler, mockSnapClient, mockState }) => { + mockRenderConfirmTransactionRequest.mockResolvedValue(true); + + await handler.confirmTransactionRequest({ + ...defaultParams, + origin: METAMASK_ORIGIN, + }); + + expect(mockRenderConfirmTransactionRequest).toHaveBeenCalledWith( + mockSnapClient, + mockState, + expect.objectContaining({ origin: METAMASK_ORIGIN }), + ); + }, + ); + }); + it('clears the interface ID after render completes', async () => { await withConfirmationHandler(async ({ handler, mockState }) => { mockRenderConfirmTransactionRequest.mockResolvedValue(true); diff --git a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts index f1393f6f2..74127de65 100644 --- a/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts +++ b/packages/tron-wallet-snap/src/services/confirmation/ConfirmationHandler.ts @@ -25,7 +25,6 @@ import { CONFIRM_SIGN_TRANSACTION_INTERFACE_NAME } from '../../ui/confirmation/v import type { ConfirmSignTransactionContext } from '../../ui/confirmation/views/ConfirmSignTransaction/types'; import { render as renderConfirmTransactionRequest } from '../../ui/confirmation/views/ConfirmTransactionRequest/render'; import { CONFIRM_TRANSACTION_INTERFACE_NAME } from '../../ui/confirmation/views/ConfirmTransactionRequest/types'; -import { formatOrigin } from '../../utils/formatOrigin'; import { SignTransactionRequestStruct } from '../../validation/structs'; import type { TronWalletKeyringRequest } from '../../validation/structs'; import { assertTransactionStructure } from '../../validation/transaction'; @@ -210,7 +209,12 @@ export class ConfirmationHandler { amount, fees, asset, - origin: formatOrigin(origin), + /** + * Pass the raw origin: the confirmation view formats it for display + * itself, and the security scan needs the unformatted value so it can + * still recognize the MetaMask origin. + */ + origin, accountType, transactionRawData, }, diff --git a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx index a63b68424..d24c195dd 100644 --- a/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx +++ b/packages/tron-wallet-snap/src/ui/confirmation/views/ConfirmTransactionRequest/ConfirmTransactionRequest.test.tsx @@ -201,6 +201,29 @@ describe('ConfirmTransactionRequest', () => { expect(result).toBeDefined(); }); + it('renders the MetaMask label for the canonical origin', () => { + const result = ConfirmTransactionRequest({ context: baseContext }); + const serialized = JSON.stringify(result); + + // The stored origin is the canonical lowercase one, but the user must see + // the MetaMask label. + expect(serialized).toContain('MetaMask'); + expect(serialized).not.toContain('"metamask"'); + }); + + it('renders the hostname for a dApp origin', () => { + const context: ConfirmTransactionRequestContext = { + ...baseContext, + origin: 'https://dapp.example.com', + }; + + const result = ConfirmTransactionRequest({ context }); + const serialized = JSON.stringify(result); + + expect(serialized).toContain('dapp.example.com'); + expect(serialized).not.toContain('https://dapp.example.com'); + }); + it('renders with Malicious validation', () => { const maliciousScanResult: TransactionScanResult = { ...mockScanResult, From 2e5a1a126d8e2b21e809d5ec40352f8506a0577b Mon Sep 17 00:00:00 2001 From: Frederic HENG Date: Wed, 30 Sep 2026 18:34:41 +0200 Subject: [PATCH 5/5] chore(tron): revert the manifest shasum restamp `mm-snap build` regenerates `source.shasum`, and CI already ignores shasum-only drift: require-clean-working-directory skips it and require-correct-shasum only enforces it on release PRs. Drop the restamped value so this fix does not carry a build artifact. Ratchet the coverage thresholds. --- packages/tron-wallet-snap/jest.config.js | 2 +- packages/tron-wallet-snap/snap.manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tron-wallet-snap/jest.config.js b/packages/tron-wallet-snap/jest.config.js index 0fc594399..881de0403 100644 --- a/packages/tron-wallet-snap/jest.config.js +++ b/packages/tron-wallet-snap/jest.config.js @@ -19,7 +19,7 @@ module.exports = { // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { global: { - branches: 72.63, + branches: 72.69, functions: 79.95, lines: 85.85, statements: 85.86, diff --git a/packages/tron-wallet-snap/snap.manifest.json b/packages/tron-wallet-snap/snap.manifest.json index 4768d2277..6344cb7ac 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": "w8+KXIrSQt4Klqgnc69CyflhR6PUUiZRgoOx84JriXQ=", + "shasum": "L4NZ35MXuCRWHzwx4paNtKwrBWApWCqwQZ0dpp9XeoI=", "location": { "npm": { "filePath": "dist/bundle.js",