From 096d4d26a7a34635d9257c9503f9576d8cf1778c Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 25 Sep 2024 22:31:25 -0230 Subject: [PATCH 01/46] Version v12.5.0 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 199b83700dde..13b553a3a9e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [12.5.0] + ## [12.3.0] ### Added - Added the ability to name accounts during the snap account creation flow ([#25191](https://github.com/MetaMask/metamask-extension/pull/25191)) @@ -5106,7 +5108,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.5.0...HEAD +[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...v12.5.0 [12.3.0]: https://github.com/MetaMask/metamask-extension/compare/v12.2.4...v12.3.0 [12.2.4]: https://github.com/MetaMask/metamask-extension/compare/v12.2.3...v12.2.4 [12.2.3]: https://github.com/MetaMask/metamask-extension/compare/v12.2.2...v12.2.3 diff --git a/package.json b/package.json index e98ec3a9fada..5006caa9b509 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "12.3.0", + "version": "12.5.0", "private": true, "repository": { "type": "git", From 0c1e2878f9dcfb57dfb6b2a44bea6842e6f12e7b Mon Sep 17 00:00:00 2001 From: Mathieu Artu Date: Tue, 1 Oct 2024 20:14:50 +0200 Subject: [PATCH 02/46] fix: [cherry-pick][V12.5.0] account syncing fixes (#27534) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR patches the `@metamask/profile-sync-controller` to its latest version. This patch version contains performance, analytics and bug fixes for the upcoming account syncing feature. This PR also contains a fix for account syncing analytics event names. All of these fixes were merged into develop: - https://github.com/MetaMask/metamask-extension/pull/27529 - https://github.com/MetaMask/metamask-extension/pull/27415 - https://github.com/MetaMask/metamask-extension/pull/27413 [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27482?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** 1. Create a new SRP 2. Add new accounts, rename some 3. Uninstall extension and reinstall 4. Import your previously created SRP 5. All your previously created accounts and respective names should be there! ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. --------- Co-authored-by: MetaMask Bot Co-authored-by: Ariella Vu <20778143+digiwand@users.noreply.github.com> --- app/scripts/metamask-controller.js | 4 +- lavamoat/browserify/beta/policy.json | 36 +-------------- lavamoat/browserify/flask/policy.json | 36 +-------------- lavamoat/browserify/main/policy.json | 36 +-------------- lavamoat/browserify/mmi/policy.json | 36 +-------------- package.json | 2 +- shared/constants/metametrics.ts | 4 +- yarn.lock | 66 +++++++++++++-------------- 8 files changed, 46 insertions(+), 174 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 577184ed8ede..1827c6d57b48 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1513,7 +1513,7 @@ export default class MetamaskController extends EventEmitter { onAccountAdded: (profileId) => { this.metaMetricsController.trackEvent({ category: MetaMetricsEventCategory.ProfileSyncing, - event: MetaMetricsEventName.AccountsSyncAccountAdded, + event: MetaMetricsEventName.AccountsSyncAdded, properties: { profile_id: profileId, }, @@ -1522,7 +1522,7 @@ export default class MetamaskController extends EventEmitter { onAccountNameUpdated: (profileId) => { this.metaMetricsController.trackEvent({ category: MetaMetricsEventCategory.ProfileSyncing, - event: MetaMetricsEventName.AccountsSyncAccountNameUpdated, + event: MetaMetricsEventName.AccountsSyncNameUpdated, properties: { profile_id: profileId, }, diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 911a6ff8b04a..70552b0d32a7 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1351,51 +1351,21 @@ "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": true, "@metamask/scure-bip39": true, + "@metamask/utils": true, "browserify>buffer": true } }, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": true, + "@metamask/utils": true, "browserify>buffer": true, "crypto-browserify>randombytes": true } }, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, @@ -2069,12 +2039,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 911a6ff8b04a..70552b0d32a7 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1351,51 +1351,21 @@ "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": true, "@metamask/scure-bip39": true, + "@metamask/utils": true, "browserify>buffer": true } }, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": true, + "@metamask/utils": true, "browserify>buffer": true, "crypto-browserify>randombytes": true } }, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, @@ -2069,12 +2039,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 911a6ff8b04a..70552b0d32a7 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1351,51 +1351,21 @@ "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": true, "@metamask/scure-bip39": true, + "@metamask/utils": true, "browserify>buffer": true } }, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": true, + "@metamask/utils": true, "browserify>buffer": true, "crypto-browserify>randombytes": true } }, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, @@ -2069,12 +2039,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 2fa339f5201e..2116f0a1a7c8 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1443,51 +1443,21 @@ "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": true, "@metamask/scure-bip39": true, + "@metamask/utils": true, "browserify>buffer": true } }, - "@metamask/keyring-controller>@metamask/eth-hd-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>@metamask/eth-simple-keyring": { "packages": { "@ethereumjs/tx>@ethereumjs/util": true, "@ethereumjs/tx>ethereum-cryptography": true, "@metamask/eth-sig-util": true, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": true, + "@metamask/utils": true, "browserify>buffer": true, "crypto-browserify>randombytes": true } }, - "@metamask/keyring-controller>@metamask/eth-simple-keyring>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/keyring-controller>ethereumjs-wallet": { "packages": { "@metamask/keyring-controller>ethereumjs-wallet>ethereum-cryptography": true, @@ -2161,12 +2131,10 @@ "URL": true, "URLSearchParams": true, "addEventListener": true, - "clearInterval": true, "console.error": true, "dispatchEvent": true, "fetch": true, "removeEventListener": true, - "setInterval": true, "setTimeout": true }, "packages": { diff --git a/package.json b/package.json index 5006caa9b509..53fc7beb16d4 100644 --- a/package.json +++ b/package.json @@ -344,7 +344,7 @@ "@metamask/post-message-stream": "^8.0.0", "@metamask/ppom-validator": "0.34.0", "@metamask/preinstalled-example-snap": "^0.1.0", - "@metamask/profile-sync-controller": "^0.9.1", + "@metamask/profile-sync-controller": "^0.9.4", "@metamask/providers": "^14.0.2", "@metamask/queued-request-controller": "^2.0.0", "@metamask/rate-limit-controller": "^6.0.0", diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index b69cc2c03cdc..d9287da93a12 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -507,8 +507,8 @@ export enum MetaMetricsEventName { AccountPasswordCreated = 'Account Password Created', AccountReset = 'Account Reset', AccountRenamed = 'Account Renamed', - AccountsSyncAccountAdded = 'Accounts Sync Account Added', - AccountsSyncAccountNameUpdated = 'Accounts Sync Account Name Updated', + AccountsSyncAdded = 'Accounts Sync Added', + AccountsSyncNameUpdated = 'Accounts Sync Name Updated', ActivityDetailsOpened = 'Activity Details Opened', ActivityDetailsClosed = 'Activity Details Closed', AnalyticsPreferenceSelected = 'Analytics Preference Selected', diff --git a/yarn.lock b/yarn.lock index 4a0bbee20818..e5023141d0bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5153,16 +5153,16 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-hd-keyring@npm:^7.0.1": - version: 7.0.1 - resolution: "@metamask/eth-hd-keyring@npm:7.0.1" +"@metamask/eth-hd-keyring@npm:^7.0.4": + version: 7.0.4 + resolution: "@metamask/eth-hd-keyring@npm:7.0.4" dependencies: "@ethereumjs/util": "npm:^8.1.0" - "@metamask/eth-sig-util": "npm:^7.0.0" - "@metamask/scure-bip39": "npm:^2.1.0" - "@metamask/utils": "npm:^8.1.0" + "@metamask/eth-sig-util": "npm:^7.0.3" + "@metamask/scure-bip39": "npm:^2.1.1" + "@metamask/utils": "npm:^9.2.1" ethereum-cryptography: "npm:^2.1.2" - checksum: 10/adb6aa532168db69aa8569be00942a4b62751ce6bff6ef5fbcda0646cfc6baf13c3b20ab72e12622797cb6c5d6901289be943f5b27d55a5ae4a90fa00c2a29cf + checksum: 10/493d06f55225b6f9da48ee001486e18898d6a4a3afd2cf40ff1dcae2ece42d5e96174f6a05b7c39419cb3531b530c8af294d9422195661788c5e0b687a328874 languageName: node linkType: hard @@ -5331,16 +5331,16 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-simple-keyring@npm:^6.0.1": - version: 6.0.1 - resolution: "@metamask/eth-simple-keyring@npm:6.0.1" +"@metamask/eth-simple-keyring@npm:^6.0.5": + version: 6.0.5 + resolution: "@metamask/eth-simple-keyring@npm:6.0.5" dependencies: "@ethereumjs/util": "npm:^8.1.0" - "@metamask/eth-sig-util": "npm:^7.0.0" - "@metamask/utils": "npm:^8.1.0" + "@metamask/eth-sig-util": "npm:^7.0.3" + "@metamask/utils": "npm:^9.2.1" ethereum-cryptography: "npm:^2.1.2" randombytes: "npm:^2.1.0" - checksum: 10/214470a237c9508097faad1df0de7b79300363325ca684182ea7e56d3ac06b030b9f77010b6587c281e8e113c36799f755c595d4bbcdadc45dda88f0a25f5f13 + checksum: 10/98b7bd00df25e7630324e2c762e3a03a7f199108a4dfe22e5a1938f1d01c9b2cd64ab4bb6fd242bf898624903d5a68a2e1f61c95f94a141266ab23dae8d97d21 languageName: node linkType: hard @@ -5641,9 +5641,9 @@ __metadata: languageName: node linkType: hard -"@metamask/keyring-api@npm:^8.0.0, @metamask/keyring-api@npm:^8.1.0, @metamask/keyring-api@npm:^8.1.2": - version: 8.1.2 - resolution: "@metamask/keyring-api@npm:8.1.2" +"@metamask/keyring-api@npm:^8.0.0, @metamask/keyring-api@npm:^8.1.0, @metamask/keyring-api@npm:^8.1.3": + version: 8.1.3 + resolution: "@metamask/keyring-api@npm:8.1.3" dependencies: "@metamask/snaps-sdk": "npm:^6.5.1" "@metamask/superstruct": "npm:^3.1.0" @@ -5652,29 +5652,29 @@ __metadata: bech32: "npm:^2.0.0" uuid: "npm:^9.0.1" peerDependencies: - "@metamask/providers": ">=15 <18" - checksum: 10/bddb6d8c86f39b9afef0b484b473cfff5e33c99037de6ded2bc5d04d935971bf232237121c0e1297e43f266006f9c8a0cf48aa7d5588a7c4796fc803acdcfd00 + "@metamask/providers": ^17.2.0 + checksum: 10/9857b6286760d22b1b7102ea8bdf03ebf56c71e9f0adee19a2230def6b7a9230561c1a3bfcb308735b79ab9a5afa9afd07a1617c1d165f63d193cd6a6b6e7a15 languageName: node linkType: hard -"@metamask/keyring-controller@npm:^17.1.0, @metamask/keyring-controller@npm:^17.2.1": - version: 17.2.1 - resolution: "@metamask/keyring-controller@npm:17.2.1" +"@metamask/keyring-controller@npm:^17.1.0, @metamask/keyring-controller@npm:^17.2.1, @metamask/keyring-controller@npm:^17.2.2": + version: 17.2.2 + resolution: "@metamask/keyring-controller@npm:17.2.2" dependencies: "@ethereumjs/util": "npm:^8.1.0" "@keystonehq/metamask-airgapped-keyring": "npm:^0.14.1" "@metamask/base-controller": "npm:^7.0.1" "@metamask/browser-passworder": "npm:^4.3.0" - "@metamask/eth-hd-keyring": "npm:^7.0.1" + "@metamask/eth-hd-keyring": "npm:^7.0.4" "@metamask/eth-sig-util": "npm:^7.0.1" - "@metamask/eth-simple-keyring": "npm:^6.0.1" - "@metamask/keyring-api": "npm:^8.1.0" + "@metamask/eth-simple-keyring": "npm:^6.0.5" + "@metamask/keyring-api": "npm:^8.1.3" "@metamask/message-manager": "npm:^10.1.1" "@metamask/utils": "npm:^9.1.0" async-mutex: "npm:^0.5.0" ethereumjs-wallet: "npm:^1.0.1" immer: "npm:^9.0.6" - checksum: 10/051cfc790d74a64c2e8139dbcdb38e845d10f3a3a85792ece6b38b0f239057f553c6f74b49e79dd6748093f1bf3b82d484d927aead3aa891247839b1fac8df66 + checksum: 10/3c3cec4c813de78c889c38b9a5f6201929743544a28c9e734bbf57a3774e3c2bc9432bb3cefa69bb7ed3580933898329c8a5e374c21c07ea204ee19bf094c8ff languageName: node linkType: hard @@ -6053,13 +6053,13 @@ __metadata: languageName: node linkType: hard -"@metamask/profile-sync-controller@npm:^0.9.1": - version: 0.9.1 - resolution: "@metamask/profile-sync-controller@npm:0.9.1" +"@metamask/profile-sync-controller@npm:^0.9.4": + version: 0.9.4 + resolution: "@metamask/profile-sync-controller@npm:0.9.4" dependencies: "@metamask/base-controller": "npm:^7.0.1" - "@metamask/keyring-api": "npm:^8.1.2" - "@metamask/keyring-controller": "npm:^17.2.1" + "@metamask/keyring-api": "npm:^8.1.3" + "@metamask/keyring-controller": "npm:^17.2.2" "@metamask/snaps-sdk": "npm:^6.5.0" "@metamask/snaps-utils": "npm:^8.1.1" "@noble/ciphers": "npm:^0.5.2" @@ -6071,7 +6071,7 @@ __metadata: "@metamask/accounts-controller": ^18.1.1 "@metamask/keyring-controller": ^17.2.0 "@metamask/snaps-controllers": ^9.7.0 - checksum: 10/9f0c22e136a526527ec3a147084024b6d5a20219894166f00fc6b22d1554f61f19b357ccbdd32973745e03ab0481d1908295309870f723e7d3bf06f720569d8a + checksum: 10/86079da552eed316f2754bd899047de1d8d9d15d390c9cdee0aef66b95bea708b5c7929a8d8d946210cc0e4c52347fee971a5cf5130149d0ca60abdc85f47774 languageName: node linkType: hard @@ -6188,7 +6188,7 @@ __metadata: languageName: node linkType: hard -"@metamask/scure-bip39@npm:^2.0.3, @metamask/scure-bip39@npm:^2.1.0, @metamask/scure-bip39@npm:^2.1.1": +"@metamask/scure-bip39@npm:^2.0.3, @metamask/scure-bip39@npm:^2.1.1": version: 2.1.1 resolution: "@metamask/scure-bip39@npm:2.1.1" dependencies: @@ -26138,7 +26138,7 @@ __metadata: "@metamask/post-message-stream": "npm:^8.0.0" "@metamask/ppom-validator": "npm:0.34.0" "@metamask/preinstalled-example-snap": "npm:^0.1.0" - "@metamask/profile-sync-controller": "npm:^0.9.1" + "@metamask/profile-sync-controller": "npm:^0.9.4" "@metamask/providers": "npm:^14.0.2" "@metamask/queued-request-controller": "npm:^2.0.0" "@metamask/rate-limit-controller": "npm:^6.0.0" From 41e788923c96d5f5ae9c5a009c40afa230fc7b2a Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 7 Oct 2024 13:56:58 +0200 Subject: [PATCH 03/46] cherry-pick: Recreate offscreen document if it already exists (#27653) ## **Description** When the service worker is stopped it doesn't seem to guarantee that the offscreen document is closed as well. Our current initialization logic assumes this and thus once the service worker is spun back up, all communication with the offscreen document fails due to initialization failure. This PR cherry-picks https://github.com/MetaMask/metamask-extension/commit/03cd7d55e0a1d529655b38976dc8bb7e6f6ae08b to the 12.5 RC, fixing this problem. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27596?quickstart=1) --- app/scripts/offscreen.js | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/app/scripts/offscreen.js b/app/scripts/offscreen.js index f09fcbcf0f58..67dcb43fb38f 100644 --- a/app/scripts/offscreen.js +++ b/app/scripts/offscreen.js @@ -5,6 +5,27 @@ import { } from '../../shared/constants/offscreen-communication'; import { getSocketBackgroundToMocha } from '../../test/e2e/background-socket/socket-background-to-mocha'; +/** + * Returns whether the offscreen document already exists or not. + * + * See https://developer.chrome.com/docs/extensions/reference/api/offscreen#before_chrome_116_check_if_an_offscreen_document_is_open + * + * @returns True if the offscreen document already is has been opened, otherwise false. + */ +async function hasOffscreenDocument() { + const { chrome, clients } = globalThis; + // getContexts is only available in Chrome 116+ + if ('getContexts' in chrome.runtime) { + const contexts = await chrome.runtime.getContexts({ + contextTypes: ['OFFSCREEN_DOCUMENT'], + }); + return contexts.length > 0; + } + const matchedClients = await clients.matchAll(); + const url = chrome.runtime.getURL('offscreen.html'); + return matchedClients.some((client) => client.url === url); +} + /** * Creates an offscreen document that can be used to load additional scripts * and iframes that can communicate with the extension through the chrome @@ -41,6 +62,14 @@ export async function createOffscreen() { }); try { + const offscreenExists = await hasOffscreenDocument(); + + // In certain cases the offscreen document may already exist during boot, if it does, we close it and recreate it. + if (offscreenExists) { + console.debug('Found existing offscreen document, closing.'); + await chrome.offscreen.closeDocument(); + } + await chrome.offscreen.createDocument({ url: './offscreen.html', reasons: ['IFRAME_SCRIPTING'], @@ -51,18 +80,10 @@ export async function createOffscreen() { if (offscreenDocumentLoadedListener) { chrome.runtime.onMessage.removeListener(offscreenDocumentLoadedListener); } - if ( - error?.message?.startsWith( - 'Only a single offscreen document may be created', - ) - ) { - console.debug('Offscreen document already exists; skipping creation'); - } else { - // Report unrecongized errors without halting wallet initialization - // Failures to create the offscreen document does not compromise wallet data integrity or - // core functionality, it's just needed for specific features. - captureException(error); - } + // Report unrecongized errors without halting wallet initialization + // Failures to create the offscreen document does not compromise wallet data integrity or + // core functionality, it's just needed for specific features. + captureException(error); return; } From be0396df50b2f8e68d18b97153bf231ceead3363 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Mon, 7 Oct 2024 14:17:01 -0230 Subject: [PATCH 04/46] feat: Double Sentry performance trace sample rate (#27468) (#27663) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cherry-pick of #27468 for v12.5.0. Original description below: ## **Description** The Sentry trace sample rate for production has been doubled, to take advantage of increased Sentry transaction quotas for our account. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27468?quickstart=1) ## **Related issues** Closes #27467 ## **Manual testing steps** It's not easy to test this because it's probabilistic. ## **Screenshots/Recordings** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. --- app/scripts/lib/setupSentry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 30d9bd34671b..d336d2bb899c 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -123,7 +123,7 @@ function getTracesSampleRate(sentryTarget) { return 1.0; } - return 0.01; + return 0.02; } /** From 160f6dd114aa6a6ed5604f2723ca02045a622606 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 7 Oct 2024 15:14:16 -0230 Subject: [PATCH 05/46] Lint fix --- ui/components/app/wallet-overview/coin-overview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/wallet-overview/coin-overview.tsx b/ui/components/app/wallet-overview/coin-overview.tsx index c5cb4e8c1f73..537c45656fe5 100644 --- a/ui/components/app/wallet-overview/coin-overview.tsx +++ b/ui/components/app/wallet-overview/coin-overview.tsx @@ -10,9 +10,9 @@ import { zeroAddress } from 'ethereumjs-util'; import { CaipChainId } from '@metamask/utils'; import type { Hex } from '@metamask/utils'; +///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import { Icon, IconName, IconSize } from '../../component-library'; import { IconColor } from '../../../helpers/constants/design-system'; -///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) import { getPortfolioUrl } from '../../../helpers/utils/portfolio'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { From b161946647cc2d3f6ac4796171dac02bf424f46d Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 7 Oct 2024 15:14:51 -0230 Subject: [PATCH 06/46] Lint changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02a3a4f90a6a..42641c2e31ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [12.5.0] + ## [12.4.0] ### Fixed - fix: flaky test `Test Snap Interactive UI test interactive ui elements` ([#26792](https://github.com/MetaMask/metamask-extension/pull/26792)) @@ -5580,8 +5581,7 @@ Update styles and spacing on the critical error page ([#20350](https://github.c [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.5.0...HEAD -[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...v12.5.0 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.4.0...HEAD +[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.4.0...v12.5.0 [12.4.0]: https://github.com/MetaMask/metamask-extension/compare/v12.3.1...v12.4.0 [12.3.1]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...v12.3.1 [12.3.0]: https://github.com/MetaMask/metamask-extension/compare/v12.2.4...v12.3.0 From ff84f84dda8c73d85a7a2672e6b1bafa7db872f4 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Mon, 7 Oct 2024 16:10:03 -0230 Subject: [PATCH 07/46] chore: fix deps audit (#27620) (#27673) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a cherry-pick of #27620 for v12.5.0. This PR resolves a security advisory by updating the `@sentry/browser` package. Original description: ## **Description** Resolve the security advisory causing the audit CI job to fail by updating the `@sentry/browser` package. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27620?quickstart=1) ## **Related issues** N/A ## **Manual testing steps** N/A ## **Screenshots/Recordings** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. Co-authored-by: chloeYue <105063779+chloeYue@users.noreply.github.com> Co-authored-by: MetaMask Bot --- lavamoat/browserify/beta/policy.json | 5 +- lavamoat/browserify/flask/policy.json | 5 +- lavamoat/browserify/main/policy.json | 5 +- lavamoat/browserify/mmi/policy.json | 5 +- yarn.lock | 117 ++++++++++++-------------- 5 files changed, 67 insertions(+), 70 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 70552b0d32a7..2f86629ac463 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -2946,7 +2946,7 @@ }, "@sentry/browser": { "globals": { - "PerformanceObserver.supportedEntryTypes.includes": true, + "PerformanceObserver.supportedEntryTypes": true, "Request": true, "URL": true, "XMLHttpRequest.prototype": true, @@ -3043,7 +3043,8 @@ "innerWidth": true, "location.href": true, "location.origin": true, - "parent": true + "parent": true, + "setTimeout": true }, "packages": { "@sentry/browser>@sentry-internal/browser-utils": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 70552b0d32a7..2f86629ac463 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -2946,7 +2946,7 @@ }, "@sentry/browser": { "globals": { - "PerformanceObserver.supportedEntryTypes.includes": true, + "PerformanceObserver.supportedEntryTypes": true, "Request": true, "URL": true, "XMLHttpRequest.prototype": true, @@ -3043,7 +3043,8 @@ "innerWidth": true, "location.href": true, "location.origin": true, - "parent": true + "parent": true, + "setTimeout": true }, "packages": { "@sentry/browser>@sentry-internal/browser-utils": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 70552b0d32a7..2f86629ac463 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -2946,7 +2946,7 @@ }, "@sentry/browser": { "globals": { - "PerformanceObserver.supportedEntryTypes.includes": true, + "PerformanceObserver.supportedEntryTypes": true, "Request": true, "URL": true, "XMLHttpRequest.prototype": true, @@ -3043,7 +3043,8 @@ "innerWidth": true, "location.href": true, "location.origin": true, - "parent": true + "parent": true, + "setTimeout": true }, "packages": { "@sentry/browser>@sentry-internal/browser-utils": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 2116f0a1a7c8..6afdcde3f0bd 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -3038,7 +3038,7 @@ }, "@sentry/browser": { "globals": { - "PerformanceObserver.supportedEntryTypes.includes": true, + "PerformanceObserver.supportedEntryTypes": true, "Request": true, "URL": true, "XMLHttpRequest.prototype": true, @@ -3135,7 +3135,8 @@ "innerWidth": true, "location.href": true, "location.origin": true, - "parent": true + "parent": true, + "setTimeout": true }, "packages": { "@sentry/browser>@sentry-internal/browser-utils": true, diff --git a/yarn.lock b/yarn.lock index e5023141d0bb..67288b06faef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7889,64 +7889,64 @@ __metadata: languageName: node linkType: hard -"@sentry-internal/browser-utils@npm:8.19.0": - version: 8.19.0 - resolution: "@sentry-internal/browser-utils@npm:8.19.0" +"@sentry-internal/browser-utils@npm:8.33.1": + version: 8.33.1 + resolution: "@sentry-internal/browser-utils@npm:8.33.1" dependencies: - "@sentry/core": "npm:8.19.0" - "@sentry/types": "npm:8.19.0" - "@sentry/utils": "npm:8.19.0" - checksum: 10/d6df6cb6edc6b2ddb7362daee39770a51b255d343b3dcb80dc98f77dc43a7cc66f29076e14d1a0ac162a51a4f620b876493a04c23a530f57170009364b6464ea + "@sentry/core": "npm:8.33.1" + "@sentry/types": "npm:8.33.1" + "@sentry/utils": "npm:8.33.1" + checksum: 10/aed6ec58a2dea3613011c24c1e1f14899eaba721d4523ca7da281cbf70e1d48e5ab2bd50da17de76e8cc8052b983840d937e167ea980c6a07e4d32f0e374903c languageName: node linkType: hard -"@sentry-internal/feedback@npm:8.19.0": - version: 8.19.0 - resolution: "@sentry-internal/feedback@npm:8.19.0" +"@sentry-internal/feedback@npm:8.33.1": + version: 8.33.1 + resolution: "@sentry-internal/feedback@npm:8.33.1" dependencies: - "@sentry/core": "npm:8.19.0" - "@sentry/types": "npm:8.19.0" - "@sentry/utils": "npm:8.19.0" - checksum: 10/e10cf1f63d49a41072aaa1b7b007241a273bd4bfa6d2c628e50d621c8cde836e6743bdefbf9ba7e96684b6dd18ad49e17841f4420fc33757e7c119ec88b4ac15 + "@sentry/core": "npm:8.33.1" + "@sentry/types": "npm:8.33.1" + "@sentry/utils": "npm:8.33.1" + checksum: 10/2cb3f4c4b71f8cdf8bcab9251216b15e0caaae257bbce49fffcf053716fab60d61793898c221457e518b109e6319faf8190c2d0e57fcea8b91f28e5815f4e643 languageName: node linkType: hard -"@sentry-internal/replay-canvas@npm:8.19.0": - version: 8.19.0 - resolution: "@sentry-internal/replay-canvas@npm:8.19.0" +"@sentry-internal/replay-canvas@npm:8.33.1": + version: 8.33.1 + resolution: "@sentry-internal/replay-canvas@npm:8.33.1" dependencies: - "@sentry-internal/replay": "npm:8.19.0" - "@sentry/core": "npm:8.19.0" - "@sentry/types": "npm:8.19.0" - "@sentry/utils": "npm:8.19.0" - checksum: 10/1f379c141884b448c56fcd663b8acc0ff1c12d50a2b9db37f9552eb2bc8c99a970114f80e58c8c4fcd61f933f9a15f58dc6cbe6f4297bb574d6772be8f41c5bf + "@sentry-internal/replay": "npm:8.33.1" + "@sentry/core": "npm:8.33.1" + "@sentry/types": "npm:8.33.1" + "@sentry/utils": "npm:8.33.1" + checksum: 10/75432f627a73bad2e09ad2a7b7200c1ea4fe9d9e797458615850689dd7b017f38c876f4435ea548da9ae7653f55be90d58fc115897febacc53b69e6593867afb languageName: node linkType: hard -"@sentry-internal/replay@npm:8.19.0": - version: 8.19.0 - resolution: "@sentry-internal/replay@npm:8.19.0" +"@sentry-internal/replay@npm:8.33.1": + version: 8.33.1 + resolution: "@sentry-internal/replay@npm:8.33.1" dependencies: - "@sentry-internal/browser-utils": "npm:8.19.0" - "@sentry/core": "npm:8.19.0" - "@sentry/types": "npm:8.19.0" - "@sentry/utils": "npm:8.19.0" - checksum: 10/dc9bef6997d1f40fb0402f52c9d14f72cf050ec140fda27e00057c59ddd1a6144e78e40aeb5e0223dd48651bf02f809db26cf6e866dd5c8ec5c6bbbf76c6f1aa + "@sentry-internal/browser-utils": "npm:8.33.1" + "@sentry/core": "npm:8.33.1" + "@sentry/types": "npm:8.33.1" + "@sentry/utils": "npm:8.33.1" + checksum: 10/05cdb361ccde5039c7353877a95eb15e4d630d5edbb874cd55ac190ee8256a1456e1c6cae37636df55bff10fcde6ff1232d8ca290467d43393bb18d9e4efe99f languageName: node linkType: hard "@sentry/browser@npm:^8.19.0": - version: 8.19.0 - resolution: "@sentry/browser@npm:8.19.0" + version: 8.33.1 + resolution: "@sentry/browser@npm:8.33.1" dependencies: - "@sentry-internal/browser-utils": "npm:8.19.0" - "@sentry-internal/feedback": "npm:8.19.0" - "@sentry-internal/replay": "npm:8.19.0" - "@sentry-internal/replay-canvas": "npm:8.19.0" - "@sentry/core": "npm:8.19.0" - "@sentry/types": "npm:8.19.0" - "@sentry/utils": "npm:8.19.0" - checksum: 10/2412e938454bd5cc505bbbe7092a17bf5fde4b222ecfedaf3d54fb963a6c875c78661921d8f6e998498c85a9a52e616db75fd706867f76d38bf3f95714775aa6 + "@sentry-internal/browser-utils": "npm:8.33.1" + "@sentry-internal/feedback": "npm:8.33.1" + "@sentry-internal/replay": "npm:8.33.1" + "@sentry-internal/replay-canvas": "npm:8.33.1" + "@sentry/core": "npm:8.33.1" + "@sentry/types": "npm:8.33.1" + "@sentry/utils": "npm:8.33.1" + checksum: 10/085717b19c89184fad0c9e17dee679401ff87616678f952d91afff574ebcc56114845c216bbbd7b81c93d54c2a42b3db4232af1c707843424cdd6800a99030a5 languageName: node linkType: hard @@ -7965,36 +7965,29 @@ __metadata: languageName: node linkType: hard -"@sentry/core@npm:8.19.0": - version: 8.19.0 - resolution: "@sentry/core@npm:8.19.0" +"@sentry/core@npm:8.33.1": + version: 8.33.1 + resolution: "@sentry/core@npm:8.33.1" dependencies: - "@sentry/types": "npm:8.19.0" - "@sentry/utils": "npm:8.19.0" - checksum: 10/708ef5abd81a9ab5288a4b258411e78591a7fec4854fc582c34f087fce62f5cd74e1086fbbc27a9f55da77d113dde137fbf9649f5b7df3d1a22886850702adbd + "@sentry/types": "npm:8.33.1" + "@sentry/utils": "npm:8.33.1" + checksum: 10/dbd781777f5dc003e21680919d37e308a64320776c54a5712163f72d4c0c4d5d25d7f07b83123e517c333fcdefb92ac5a0f15cb4dbbc79f3cc7309038cb0fcbb languageName: node linkType: hard -"@sentry/types@npm:8.19.0": - version: 8.19.0 - resolution: "@sentry/types@npm:8.19.0" - checksum: 10/8812f7394c6c031197abc04d80e5b5b3693742dc065b877c535a9ceb538aabd60ee27fc2b13824e2b8fc264819868109bbd4de3642fd1c7bf30d304fb0c21aa9 +"@sentry/types@npm:8.33.1, @sentry/types@npm:^8.19.0": + version: 8.33.1 + resolution: "@sentry/types@npm:8.33.1" + checksum: 10/bcd7f80e84a23cb810fa5819dc85f45bd62d52b01b1f64a1b31297df21e9d1f4de8f7ea91835c5d6a7010d7dbfc8b09cd708d057d345a6ff685b7f12db41ae57 languageName: node linkType: hard -"@sentry/types@npm:^8.19.0": - version: 8.20.0 - resolution: "@sentry/types@npm:8.20.0" - checksum: 10/c7d7ed17975f0fc0b4bf5aece58084953c2a76e8f417923a476fe1fd42a2c9339c548d701edbc4b938c9252cf680d3eff4c6c2a986bc7ac62649aebf656c5b64 - languageName: node - linkType: hard - -"@sentry/utils@npm:8.19.0, @sentry/utils@npm:^8.19.0": - version: 8.19.0 - resolution: "@sentry/utils@npm:8.19.0" +"@sentry/utils@npm:8.33.1, @sentry/utils@npm:^8.19.0": + version: 8.33.1 + resolution: "@sentry/utils@npm:8.33.1" dependencies: - "@sentry/types": "npm:8.19.0" - checksum: 10/abd507e5b37c7753534865f74a1a622fdbe2d71cfa61fd009703f4c9c90634fb6d26e3b2f8e09904631d4692e3735de451ed914c505c31700a6f5504a61e649e + "@sentry/types": "npm:8.33.1" + checksum: 10/79426deba11c043f0410b4b5d635367147d7e41bb90526168f180ae05598768348de39a82f89a92a4f0365f5ece5f62950ba6eab0b7300faefea7a9bb0889df3 languageName: node linkType: hard From 073c9fe2b2f19a5e9c09fb346244b74f4776bbfe Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Fri, 11 Oct 2024 10:14:17 +0100 Subject: [PATCH 08/46] perf (cherry-pick): add tags to UI startup trace (#27550) (#27727) --- app/scripts/lib/setupSentry.js | 3 +- package.json | 6 +- shared/lib/trace.test.ts | 38 ++++-- shared/lib/trace.ts | 133 ++++++++++++++++++++- ui/helpers/utils/tags.test.ts | 206 +++++++++++++++++++++++++++++++++ ui/helpers/utils/tags.ts | 42 +++++++ ui/index.js | 9 +- ui/selectors/nft.test.ts | 2 + ui/selectors/nft.ts | 37 +++++- ui/selectors/selectors.js | 18 +++ ui/store/store.ts | 85 +++++++------- yarn.lock | 12 +- 12 files changed, 526 insertions(+), 65 deletions(-) create mode 100644 ui/helpers/utils/tags.test.ts create mode 100644 ui/helpers/utils/tags.ts diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 22148e0b8cff..55d04bfb0754 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -291,7 +291,7 @@ async function getMetaMetricsEnabled() { function setSentryClient() { const clientOptions = getClientOptions(); - const { dsn, environment, release } = clientOptions; + const { dsn, environment, release, tracesSampleRate } = clientOptions; /** * Sentry throws on initialization as it wants to avoid polluting the global namespace and @@ -311,6 +311,7 @@ function setSentryClient() { environment, dsn, release, + tracesSampleRate, }); Sentry.registerSpanErrorInstrumentation(); diff --git a/package.json b/package.json index 53fc7beb16d4..0dde5bc76ba2 100644 --- a/package.json +++ b/package.json @@ -367,9 +367,9 @@ "@popperjs/core": "^2.4.0", "@reduxjs/toolkit": "patch:@reduxjs/toolkit@npm%3A1.9.7#~/.yarn/patches/@reduxjs-toolkit-npm-1.9.7-b14925495c.patch", "@segment/loosely-validate-event": "^2.0.0", - "@sentry/browser": "^8.19.0", - "@sentry/types": "^8.19.0", - "@sentry/utils": "^8.19.0", + "@sentry/browser": "^8.33.1", + "@sentry/types": "^8.33.1", + "@sentry/utils": "^8.33.1", "@swc/core": "1.4.11", "@trezor/connect-web": "patch:@trezor/connect-web@npm%3A9.3.0#~/.yarn/patches/@trezor-connect-web-npm-9.3.0-040ab10d9a.patch", "@zxing/browser": "^0.1.4", diff --git a/shared/lib/trace.test.ts b/shared/lib/trace.test.ts index 5154a930b7f9..7cd39eba03d1 100644 --- a/shared/lib/trace.test.ts +++ b/shared/lib/trace.test.ts @@ -1,4 +1,5 @@ import { + setMeasurement, Span, startSpan, startSpanManual, @@ -10,6 +11,7 @@ jest.mock('@sentry/browser', () => ({ withIsolationScope: jest.fn(), startSpan: jest.fn(), startSpanManual: jest.fn(), + setMeasurement: jest.fn(), })); const NAME_MOCK = TraceName.Transaction; @@ -32,7 +34,8 @@ describe('Trace', () => { const startSpanMock = jest.mocked(startSpan); const startSpanManualMock = jest.mocked(startSpanManual); const withIsolationScopeMock = jest.mocked(withIsolationScope); - const setTagsMock = jest.fn(); + const setMeasurementMock = jest.mocked(setMeasurement); + const setTagMock = jest.fn(); beforeEach(() => { jest.resetAllMocks(); @@ -41,13 +44,20 @@ describe('Trace', () => { startSpan: startSpanMock, startSpanManual: startSpanManualMock, withIsolationScope: withIsolationScopeMock, + setMeasurement: setMeasurementMock, }; startSpanMock.mockImplementation((_, fn) => fn({} as Span)); + startSpanManualMock.mockImplementation((_, fn) => + fn({} as Span, () => { + // Intentionally empty + }), + ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any withIsolationScopeMock.mockImplementation((fn: any) => - fn({ setTags: setTagsMock }), + fn({ setTag: setTagMock }), ); }); @@ -91,8 +101,12 @@ describe('Trace', () => { expect.any(Function), ); - expect(setTagsMock).toHaveBeenCalledTimes(1); - expect(setTagsMock).toHaveBeenCalledWith(TAGS_MOCK); + expect(setTagMock).toHaveBeenCalledTimes(2); + expect(setTagMock).toHaveBeenCalledWith('tag1', 'value1'); + expect(setTagMock).toHaveBeenCalledWith('tag2', true); + + expect(setMeasurementMock).toHaveBeenCalledTimes(1); + expect(setMeasurementMock).toHaveBeenCalledWith('tag3', 123, 'none'); }); it('invokes Sentry if no callback provided', () => { @@ -117,8 +131,12 @@ describe('Trace', () => { expect.any(Function), ); - expect(setTagsMock).toHaveBeenCalledTimes(1); - expect(setTagsMock).toHaveBeenCalledWith(TAGS_MOCK); + expect(setTagMock).toHaveBeenCalledTimes(2); + expect(setTagMock).toHaveBeenCalledWith('tag1', 'value1'); + expect(setTagMock).toHaveBeenCalledWith('tag2', true); + + expect(setMeasurementMock).toHaveBeenCalledTimes(1); + expect(setMeasurementMock).toHaveBeenCalledWith('tag3', 123, 'none'); }); it('invokes Sentry if no callback provided with custom start time', () => { @@ -145,8 +163,12 @@ describe('Trace', () => { expect.any(Function), ); - expect(setTagsMock).toHaveBeenCalledTimes(1); - expect(setTagsMock).toHaveBeenCalledWith(TAGS_MOCK); + expect(setTagMock).toHaveBeenCalledTimes(2); + expect(setTagMock).toHaveBeenCalledWith('tag1', 'value1'); + expect(setTagMock).toHaveBeenCalledWith('tag2', true); + + expect(setMeasurementMock).toHaveBeenCalledTimes(1); + expect(setMeasurementMock).toHaveBeenCalledWith('tag3', 123, 'none'); }); }); diff --git a/shared/lib/trace.ts b/shared/lib/trace.ts index e51c2d3cbdcf..b3e6e9f90168 100644 --- a/shared/lib/trace.ts +++ b/shared/lib/trace.ts @@ -1,10 +1,13 @@ import * as Sentry from '@sentry/browser'; -import { Primitive, StartSpanOptions } from '@sentry/types'; +import { MeasurementUnit, StartSpanOptions } from '@sentry/types'; import { createModuleLogger } from '@metamask/utils'; // TODO: Remove restricted import // eslint-disable-next-line import/no-restricted-paths import { log as sentryLogger } from '../../app/scripts/lib/setupSentry'; +/** + * The supported trace names. + */ export enum TraceName { BackgroundConnect = 'Background Connect', DeveloperTest = 'Developer Test', @@ -35,22 +38,71 @@ type PendingTrace = { startTime: number; }; +/** + * A context object to associate traces with each other and generate nested traces. + */ export type TraceContext = unknown; +/** + * A callback function that can be traced. + */ export type TraceCallback = (context?: TraceContext) => T; +/** + * A request to create a new trace. + */ export type TraceRequest = { + /** + * Custom data to associate with the trace. + */ data?: Record; + + /** + * A unique identifier when not tracing a callback. + * Defaults to 'default' if not provided. + */ id?: string; + + /** + * The name of the trace. + */ name: TraceName; + + /** + * The parent context of the trace. + * If provided, the trace will be nested under the parent trace. + */ parentContext?: TraceContext; + + /** + * Override the start time of the trace. + */ startTime?: number; + + /** + * Custom tags to associate with the trace. + */ tags?: Record; }; +/** + * A request to end a pending trace. + */ export type EndTraceRequest = { + /** + * The unique identifier of the trace. + * Defaults to 'default' if not provided. + */ id?: string; + + /** + * The name of the trace. + */ name: TraceName; + + /** + * Override the end time of the trace. + */ timestamp?: number; }; @@ -58,6 +110,16 @@ export function trace(request: TraceRequest, fn: TraceCallback): T; export function trace(request: TraceRequest): TraceContext; +/** + * Create a Sentry transaction to analyse the duration of a code flow. + * If a callback is provided, the transaction will be automatically ended when the callback completes. + * If the callback returns a promise, the transaction will be ended when the promise resolves or rejects. + * If no callback is provided, the transaction must be manually ended using `endTrace`. + * + * @param request - The data associated with the trace, such as the name and tags. + * @param fn - The optional callback to record the duration of. + * @returns The context of the trace, or the result of the callback if provided. + */ export function trace( request: TraceRequest, fn?: TraceCallback, @@ -69,6 +131,12 @@ export function trace( return traceCallback(request, fn); } +/** + * End a pending trace that was started without a callback. + * Does nothing if the pending trace cannot be found. + * + * @param request - The data necessary to identify and end the pending trace. + */ export function endTrace(request: EndTraceRequest) { const { name, timestamp } = request; const id = getTraceId(request); @@ -100,6 +168,10 @@ function traceCallback(request: TraceRequest, fn: TraceCallback): T { const start = Date.now(); let error: unknown; + if (span) { + initSpan(span, request); + } + return tryCatchMaybePromise( () => fn(span), (currentError) => { @@ -130,6 +202,10 @@ function startTrace(request: TraceRequest): TraceContext { span?.end(timestamp); }; + if (span) { + initSpan(span, request); + } + const pendingTrace = { end, request, startTime }; const key = getTraceKey(request); tracesByKey.set(key, pendingTrace); @@ -148,7 +224,7 @@ function startSpan( request: TraceRequest, callback: (spanOptions: StartSpanOptions) => T, ) { - const { data: attributes, name, parentContext, startTime, tags } = request; + const { data: attributes, name, parentContext, startTime } = request; const parentSpan = (parentContext ?? null) as Sentry.Span | null; const spanOptions: StartSpanOptions = { @@ -160,8 +236,7 @@ function startSpan( }; return sentryWithIsolationScope((scope: Sentry.Scope) => { - scope.setTags(tags as Record); - + initScope(scope, request); return callback(spanOptions); }); } @@ -181,6 +256,40 @@ function getPerformanceTimestamp(): number { return performance.timeOrigin + performance.now(); } +/** + * Initialise the isolated Sentry scope created for each trace. + * Includes setting all non-numeric tags. + * + * @param scope - The Sentry scope to initialise. + * @param request - The trace request. + */ +function initScope(scope: Sentry.Scope, request: TraceRequest) { + const tags = request.tags ?? {}; + + for (const [key, value] of Object.entries(tags)) { + if (typeof value !== 'number') { + scope.setTag(key, value); + } + } +} + +/** + * Initialise the Sentry span created for each trace. + * Includes setting all numeric tags as measurements so they can be queried numerically in Sentry. + * + * @param _span - The Sentry span to initialise. + * @param request - The trace request. + */ +function initSpan(_span: Sentry.Span, request: TraceRequest) { + const tags = request.tags ?? {}; + + for (const [key, value] of Object.entries(tags)) { + if (typeof value === 'number') { + sentrySetMeasurement(key, value, 'none'); + } + } +} + function tryCatchMaybePromise( tryFn: () => T, catchFn: (error: unknown) => void, @@ -242,7 +351,7 @@ function sentryWithIsolationScope(callback: (scope: Sentry.Scope) => T): T { if (!actual) { const scope = { // eslint-disable-next-line no-empty-function - setTags: () => {}, + setTag: () => {}, } as unknown as Sentry.Scope; return callback(scope); @@ -250,3 +359,17 @@ function sentryWithIsolationScope(callback: (scope: Sentry.Scope) => T): T { return actual(callback); } + +function sentrySetMeasurement( + key: string, + value: number, + unit: MeasurementUnit, +) { + const actual = globalThis.sentry?.setMeasurement; + + if (!actual) { + return; + } + + actual(key, value, unit); +} diff --git a/ui/helpers/utils/tags.test.ts b/ui/helpers/utils/tags.test.ts new file mode 100644 index 000000000000..eae5e90f9ea1 --- /dev/null +++ b/ui/helpers/utils/tags.test.ts @@ -0,0 +1,206 @@ +// TODO: Remove restricted import +// eslint-disable-next-line import/no-restricted-paths +import { getEnvironmentType } from '../../../app/scripts/lib/util'; +import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../shared/constants/app'; +import { MetaMaskReduxState } from '../../store/store'; +import { getStartupTraceTags } from './tags'; + +jest.mock('../../../app/scripts/lib/util', () => ({ + ...jest.requireActual('../../../app/scripts/lib/util'), + getEnvironmentType: jest.fn(), +})); + +const STATE_EMPTY_MOCK = { + metamask: { + allTokens: {}, + internalAccounts: { + accounts: {}, + }, + metamaskNotificationsList: [], + }, +} as unknown as MetaMaskReduxState; + +function createMockState( + metamaskState: Partial, +): MetaMaskReduxState { + return { + ...STATE_EMPTY_MOCK, + metamask: { + ...STATE_EMPTY_MOCK.metamask, + ...metamaskState, + }, + }; +} + +describe('Tags Utils', () => { + const getEnvironmentTypeMock = jest.mocked(getEnvironmentType); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + describe('getStartupTraceTags', () => { + it('includes UI type', () => { + getEnvironmentTypeMock.mockReturnValue(ENVIRONMENT_TYPE_FULLSCREEN); + + const tags = getStartupTraceTags(STATE_EMPTY_MOCK); + + expect(tags['wallet.ui_type']).toStrictEqual(ENVIRONMENT_TYPE_FULLSCREEN); + }); + + it('includes if unlocked', () => { + const state = createMockState({ isUnlocked: true }); + const tags = getStartupTraceTags(state); + + expect(tags['wallet.unlocked']).toStrictEqual(true); + }); + + it('includes if not unlocked', () => { + const state = createMockState({ isUnlocked: false }); + const tags = getStartupTraceTags(state); + + expect(tags['wallet.unlocked']).toStrictEqual(false); + }); + + it('includes pending approval type', () => { + const state = createMockState({ + pendingApprovals: { + 1: { + type: 'eth_sendTransaction', + }, + } as unknown as MetaMaskReduxState['metamask']['pendingApprovals'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.pending_approval']).toStrictEqual( + 'eth_sendTransaction', + ); + }); + + it('includes first pending approval type if multiple', () => { + const state = createMockState({ + pendingApprovals: { + 1: { + type: 'eth_sendTransaction', + }, + 2: { + type: 'personal_sign', + }, + } as unknown as MetaMaskReduxState['metamask']['pendingApprovals'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.pending_approval']).toStrictEqual( + 'eth_sendTransaction', + ); + }); + + it('includes account count', () => { + const state = createMockState({ + internalAccounts: { + accounts: { + '0x1234': {}, + '0x4321': {}, + }, + } as unknown as MetaMaskReduxState['metamask']['internalAccounts'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.account_count']).toStrictEqual(2); + }); + + it('includes nft count', () => { + const state = createMockState({ + allNfts: { + '0x1234': { + '0x1': [ + { + tokenId: '1', + }, + { + tokenId: '2', + }, + ], + '0x2': [ + { + tokenId: '3', + }, + { + tokenId: '4', + }, + ], + }, + '0x4321': { + '0x3': [ + { + tokenId: '5', + }, + ], + }, + } as unknown as MetaMaskReduxState['metamask']['allNfts'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.nft_count']).toStrictEqual(5); + }); + + it('includes notification count', () => { + const state = createMockState({ + metamaskNotificationsList: [ + {}, + {}, + {}, + ] as unknown as MetaMaskReduxState['metamask']['metamaskNotificationsList'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.notification_count']).toStrictEqual(3); + }); + + it('includes token count', () => { + const state = createMockState({ + allTokens: { + '0x1': { + '0x1234': [{}, {}], + '0x4321': [{}], + }, + '0x2': { + '0x5678': [{}], + }, + } as unknown as MetaMaskReduxState['metamask']['allTokens'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.token_count']).toStrictEqual(4); + }); + + it('includes transaction count', () => { + const state = createMockState({ + transactions: [ + { + id: 1, + chainId: '0x1', + }, + { + id: 2, + chainId: '0x1', + }, + { + id: 3, + chainId: '0x2', + }, + ] as unknown as MetaMaskReduxState['metamask']['transactions'], + }); + + const tags = getStartupTraceTags(state); + + expect(tags['wallet.transaction_count']).toStrictEqual(3); + }); + }); +}); diff --git a/ui/helpers/utils/tags.ts b/ui/helpers/utils/tags.ts new file mode 100644 index 000000000000..4a253e214d82 --- /dev/null +++ b/ui/helpers/utils/tags.ts @@ -0,0 +1,42 @@ +// TODO: Remove restricted import +// eslint-disable-next-line import/no-restricted-paths +import { getEnvironmentType } from '../../../app/scripts/lib/util'; +import { getIsUnlocked } from '../../ducks/metamask/metamask'; +import { + getInternalAccounts, + getPendingApprovals, + getTransactions, + selectAllTokensFlat, +} from '../../selectors'; +import { getMetamaskNotifications } from '../../selectors/metamask-notifications/metamask-notifications'; +import { selectAllNftsFlat } from '../../selectors/nft'; +import { MetaMaskReduxState } from '../../store/store'; + +/** + * Generate the required tags for the UI startup trace. + * + * @param state - The current flattened UI state. + * @returns The tags for the startup trace. + */ +export function getStartupTraceTags(state: MetaMaskReduxState) { + const uiType = getEnvironmentType(); + const unlocked = getIsUnlocked(state) as boolean; + const accountCount = getInternalAccounts(state).length; + const nftCount = selectAllNftsFlat(state).length; + const notificationCount = getMetamaskNotifications(state).length; + const tokenCount = selectAllTokensFlat(state).length as number; + const transactionCount = getTransactions(state).length; + const pendingApprovals = getPendingApprovals(state); + const firstApprovalType = pendingApprovals?.[0]?.type; + + return { + 'wallet.account_count': accountCount, + 'wallet.nft_count': nftCount, + 'wallet.notification_count': notificationCount, + 'wallet.pending_approval': firstApprovalType, + 'wallet.token_count': tokenCount, + 'wallet.transaction_count': transactionCount, + 'wallet.unlocked': unlocked, + 'wallet.ui_type': uiType, + }; +} diff --git a/ui/index.js b/ui/index.js index fec0321164dd..bc427addb55e 100644 --- a/ui/index.js +++ b/ui/index.js @@ -39,6 +39,7 @@ import { import Root from './pages'; import txHelper from './helpers/utils/tx-helper'; import { setBackgroundConnection } from './store/background-connection'; +import { getStartupTraceTags } from './helpers/utils/tags'; log.setLevel(global.METAMASK_DEBUG ? 'debug' : 'warn', false); @@ -182,8 +183,14 @@ export async function setupInitialStore( async function startApp(metamaskState, backgroundConnection, opts) { const { traceContext } = opts; + const tags = getStartupTraceTags({ metamask: metamaskState }); + const store = await trace( - { name: TraceName.SetupStore, parentContext: traceContext }, + { + name: TraceName.SetupStore, + parentContext: traceContext, + tags, + }, () => setupInitialStore(metamaskState, backgroundConnection, opts.activeTab), ); diff --git a/ui/selectors/nft.test.ts b/ui/selectors/nft.test.ts index 101eb4aae181..d6f4d956f020 100644 --- a/ui/selectors/nft.test.ts +++ b/ui/selectors/nft.test.ts @@ -38,6 +38,7 @@ describe('NFT Selectors', () => { [chainIdMock2]: [contractMock5], }, }, + allNfts: {}, }, }; @@ -80,6 +81,7 @@ describe('NFT Selectors', () => { [chainIdMock2]: [contractMock5], }, }, + allNfts: {}, }, }; diff --git a/ui/selectors/nft.ts b/ui/selectors/nft.ts index 8320c6258b1c..ab3836714923 100644 --- a/ui/selectors/nft.ts +++ b/ui/selectors/nft.ts @@ -1,14 +1,19 @@ -import { NftContract } from '@metamask/assets-controllers'; +import { Nft, NftContract } from '@metamask/assets-controllers'; import { createSelector } from 'reselect'; import { getMemoizedCurrentChainId } from './selectors'; -type NftState = { +export type NftState = { metamask: { allNftContracts: { [account: string]: { [chainId: string]: NftContract[]; }; }; + allNfts: { + [account: string]: { + [chainId: string]: Nft[]; + }; + }; }; }; @@ -16,6 +21,16 @@ function getNftContractsByChainByAccount(state: NftState) { return state.metamask.allNftContracts ?? {}; } +/** + * Get all NFTs owned by the user. + * + * @param state - Metamask state. + * @returns All NFTs owned by the user, keyed by chain ID then account address. + */ +function getNftsByChainByAccount(state: NftState) { + return state.metamask.allNfts ?? {}; +} + export const getNftContractsByAddressByChain = createSelector( getNftContractsByChainByAccount, (nftContractsByChainByAccount) => { @@ -53,3 +68,21 @@ export const getNftContractsByAddressOnCurrentChain = createSelector( return nftContractsByAddressByChain[currentChainId] ?? {}; }, ); + +/** + * Get a flattened list of all NFTs owned by the user. + * Includes all NFTs from all chains and accounts. + * + * @param state - Metamask state. + * @returns All NFTs owned by the user in a single array. + */ +export const selectAllNftsFlat = createSelector( + getNftsByChainByAccount, + (nftsByChainByAccount) => { + const nftsByChainArray = Object.values(nftsByChainByAccount); + return nftsByChainArray.reduce((acc, nftsByChain) => { + const nftsArrays = Object.values(nftsByChain); + return acc.concat(...nftsArrays); + }, []); + }, +); diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index bdc1547b7246..42ed4fecbdf4 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -490,6 +490,24 @@ export function getAllTokens(state) { return state.metamask.allTokens; } +/** + * Get a flattened list of all ERC-20 tokens owned by the user. + * Includes all tokens from all chains and accounts. + * + * @returns {object[]} All ERC-20 tokens owned by the user in a flat array. + */ +export const selectAllTokensFlat = createSelector( + getAllTokens, + (tokensByAccountByChain) => { + const tokensByAccountArray = Object.values(tokensByAccountByChain); + + return tokensByAccountArray.reduce((acc, tokensByAccount) => { + const tokensArray = Object.values(tokensByAccount); + return acc.concat(...tokensArray); + }, []); + }, +); + /** * Selector to return an origin to network ID map * diff --git a/ui/store/store.ts b/ui/store/store.ts index 6e580c137bdc..8433511380e7 100644 --- a/ui/store/store.ts +++ b/ui/store/store.ts @@ -5,6 +5,11 @@ import { ApprovalControllerState } from '@metamask/approval-controller'; import { GasEstimateType, GasFeeEstimates } from '@metamask/gas-fee-controller'; import { TransactionMeta } from '@metamask/transaction-controller'; import { InternalAccount } from '@metamask/keyring-api'; +import { + NftControllerState, + TokensControllerState, +} from '@metamask/assets-controllers'; +import { NotificationServicesControllerState } from '@metamask/notification-services-controller/notification-services'; import rootReducer from '../ducks'; import { LedgerTransportTypes } from '../../shared/constants/hardware-wallets'; import type { NetworkStatus } from '../../shared/constants/network'; @@ -45,48 +50,50 @@ export type MessagesIndexedById = { * state received from the background takes precedence over anything in the * metamask reducer. */ -type TemporaryBackgroundState = { - addressBook: { - [chainId: string]: { - name: string; - }[]; - }; - // todo: can this be deleted post network controller v20 - providerConfig: { - chainId: string; - }; - transactions: TransactionMeta[]; - ledgerTransportType: LedgerTransportTypes; - unapprovedDecryptMsgs: MessagesIndexedById; - unapprovedPersonalMsgs: MessagesIndexedById; - unapprovedTypedMessages: MessagesIndexedById; - networksMetadata: { - [NetworkClientId: string]: { - EIPS: { [eip: string]: boolean }; - status: NetworkStatus; +type TemporaryBackgroundState = NftControllerState & + NotificationServicesControllerState & + TokensControllerState & { + addressBook: { + [chainId: string]: { + name: string; + }[]; }; - }; - selectedNetworkClientId: string; - pendingApprovals: ApprovalControllerState['pendingApprovals']; - approvalFlows: ApprovalControllerState['approvalFlows']; - knownMethodData?: { - [fourBytePrefix: string]: Record; - }; - gasFeeEstimates: GasFeeEstimates; - gasEstimateType: GasEstimateType; - ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) - // TODO: Replace `any` with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - custodyAccountDetails?: { [key: string]: any }; - ///: END:ONLY_INCLUDE_IF - internalAccounts: { - accounts: { - [key: string]: InternalAccount; + // todo: can this be deleted post network controller v20 + providerConfig: { + chainId: string; + }; + transactions: TransactionMeta[]; + ledgerTransportType: LedgerTransportTypes; + unapprovedDecryptMsgs: MessagesIndexedById; + unapprovedPersonalMsgs: MessagesIndexedById; + unapprovedTypedMessages: MessagesIndexedById; + networksMetadata: { + [NetworkClientId: string]: { + EIPS: { [eip: string]: boolean }; + status: NetworkStatus; + }; + }; + selectedNetworkClientId: string; + pendingApprovals: ApprovalControllerState['pendingApprovals']; + approvalFlows: ApprovalControllerState['approvalFlows']; + knownMethodData?: { + [fourBytePrefix: string]: Record; }; - selectedAccount: string; + gasFeeEstimates: GasFeeEstimates; + gasEstimateType: GasEstimateType; + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + custodyAccountDetails?: { [key: string]: any }; + ///: END:ONLY_INCLUDE_IF + internalAccounts: { + accounts: { + [key: string]: InternalAccount; + }; + selectedAccount: string; + }; + keyrings: { type: string; accounts: string[] }[]; }; - keyrings: { type: string; accounts: string[] }[]; -}; type RootReducerReturnType = ReturnType; diff --git a/yarn.lock b/yarn.lock index 67288b06faef..2004eb198b88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7935,7 +7935,7 @@ __metadata: languageName: node linkType: hard -"@sentry/browser@npm:^8.19.0": +"@sentry/browser@npm:^8.33.1": version: 8.33.1 resolution: "@sentry/browser@npm:8.33.1" dependencies: @@ -7975,14 +7975,14 @@ __metadata: languageName: node linkType: hard -"@sentry/types@npm:8.33.1, @sentry/types@npm:^8.19.0": +"@sentry/types@npm:8.33.1, @sentry/types@npm:^8.33.1": version: 8.33.1 resolution: "@sentry/types@npm:8.33.1" checksum: 10/bcd7f80e84a23cb810fa5819dc85f45bd62d52b01b1f64a1b31297df21e9d1f4de8f7ea91835c5d6a7010d7dbfc8b09cd708d057d345a6ff685b7f12db41ae57 languageName: node linkType: hard -"@sentry/utils@npm:8.33.1, @sentry/utils@npm:^8.19.0": +"@sentry/utils@npm:8.33.1, @sentry/utils@npm:^8.33.1": version: 8.33.1 resolution: "@sentry/utils@npm:8.33.1" dependencies: @@ -26163,10 +26163,10 @@ __metadata: "@popperjs/core": "npm:^2.4.0" "@reduxjs/toolkit": "patch:@reduxjs/toolkit@npm%3A1.9.7#~/.yarn/patches/@reduxjs-toolkit-npm-1.9.7-b14925495c.patch" "@segment/loosely-validate-event": "npm:^2.0.0" - "@sentry/browser": "npm:^8.19.0" + "@sentry/browser": "npm:^8.33.1" "@sentry/cli": "npm:^2.19.4" - "@sentry/types": "npm:^8.19.0" - "@sentry/utils": "npm:^8.19.0" + "@sentry/types": "npm:^8.33.1" + "@sentry/utils": "npm:^8.33.1" "@storybook/addon-a11y": "npm:^7.6.20" "@storybook/addon-actions": "npm:^7.6.20" "@storybook/addon-designs": "npm:^7.0.9" From 0736532798a7a9ecfa1079aa8c06002675398b70 Mon Sep 17 00:00:00 2001 From: Mathieu Artu Date: Fri, 11 Oct 2024 13:55:21 +0200 Subject: [PATCH 09/46] fix: [cherry-pick][V12.5.0] account syncing bugfix (#27761) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR bumps `@metamask/profile-sync-controller` to version `0.9.7`. This version fixes an account sync bug where we would save imported accounts in user storage. This is a cherry pick for: PR: https://github.com/MetaMask/metamask-extension/pull/27749 Commit: https://github.com/MetaMask/metamask-extension/commit/86525fd7cf9cf246feb408e35b71beecd03a5b2c [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27761?quickstart=1) ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/NOTIFY-1215 ## **Manual testing steps** 1. Create a new SRP 2. Add new accounts, rename some 3. Uninstall extension and reinstall 4. Import your previously created SRP 5. All your previously created accounts and respective names should be there! ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. --------- Co-authored-by: MetaMask Bot --- lavamoat/browserify/beta/policy.json | 1 + lavamoat/browserify/flask/policy.json | 1 + lavamoat/browserify/main/policy.json | 1 + lavamoat/browserify/mmi/policy.json | 1 + package.json | 2 +- yarn.lock | 10 +++++----- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 2f86629ac463..bf47338c68a1 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -2036,6 +2036,7 @@ "Event": true, "Headers": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "URLSearchParams": true, "addEventListener": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 2f86629ac463..bf47338c68a1 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -2036,6 +2036,7 @@ "Event": true, "Headers": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "URLSearchParams": true, "addEventListener": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 2f86629ac463..bf47338c68a1 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -2036,6 +2036,7 @@ "Event": true, "Headers": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "URLSearchParams": true, "addEventListener": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 6afdcde3f0bd..54d61c2e245c 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -2128,6 +2128,7 @@ "Event": true, "Headers": true, "TextDecoder": true, + "TextEncoder": true, "URL": true, "URLSearchParams": true, "addEventListener": true, diff --git a/package.json b/package.json index 0dde5bc76ba2..bde7fa9853b8 100644 --- a/package.json +++ b/package.json @@ -344,7 +344,7 @@ "@metamask/post-message-stream": "^8.0.0", "@metamask/ppom-validator": "0.34.0", "@metamask/preinstalled-example-snap": "^0.1.0", - "@metamask/profile-sync-controller": "^0.9.4", + "@metamask/profile-sync-controller": "^0.9.7", "@metamask/providers": "^14.0.2", "@metamask/queued-request-controller": "^2.0.0", "@metamask/rate-limit-controller": "^6.0.0", diff --git a/yarn.lock b/yarn.lock index 2004eb198b88..08b76a2b2048 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6053,9 +6053,9 @@ __metadata: languageName: node linkType: hard -"@metamask/profile-sync-controller@npm:^0.9.4": - version: 0.9.4 - resolution: "@metamask/profile-sync-controller@npm:0.9.4" +"@metamask/profile-sync-controller@npm:^0.9.7": + version: 0.9.7 + resolution: "@metamask/profile-sync-controller@npm:0.9.7" dependencies: "@metamask/base-controller": "npm:^7.0.1" "@metamask/keyring-api": "npm:^8.1.3" @@ -6071,7 +6071,7 @@ __metadata: "@metamask/accounts-controller": ^18.1.1 "@metamask/keyring-controller": ^17.2.0 "@metamask/snaps-controllers": ^9.7.0 - checksum: 10/86079da552eed316f2754bd899047de1d8d9d15d390c9cdee0aef66b95bea708b5c7929a8d8d946210cc0e4c52347fee971a5cf5130149d0ca60abdc85f47774 + checksum: 10/e53888533b2aae937bbe4e385dca2617c324b34e3e60af218cd98c26d514fb725f4c67b649f126e055f6a50a554817b229d37488115b98d70e8aee7b3a910bde languageName: node linkType: hard @@ -26131,7 +26131,7 @@ __metadata: "@metamask/post-message-stream": "npm:^8.0.0" "@metamask/ppom-validator": "npm:0.34.0" "@metamask/preinstalled-example-snap": "npm:^0.1.0" - "@metamask/profile-sync-controller": "npm:^0.9.4" + "@metamask/profile-sync-controller": "npm:^0.9.7" "@metamask/providers": "npm:^14.0.2" "@metamask/queued-request-controller": "npm:^2.0.0" "@metamask/rate-limit-controller": "npm:^6.0.0" From ce5d7d195f458049ab981ee95357200e301b5245 Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Mon, 14 Oct 2024 16:54:04 -0500 Subject: [PATCH 10/46] cherry-pick: "revert: use networkClientId to resolve chainId in PPOM Middleware (#27570)" (#27848) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts [this PPOM change](https://github.com/MetaMask/metamask-extension/pull/27263) due to [issue with network configuration for the newly added rpc endpoint not being available when queried immediately after being added](https://github.com/MetaMask/metamask-extension/issues/27447) [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27570?quickstart=1) Fixes: 1. Go to this page... 2. 3. - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] 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. ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27848?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **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/develop/.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/develop/.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. Co-authored-by: jiexi --- app/scripts/lib/ppom/ppom-middleware.test.ts | 140 +++++++++++-------- app/scripts/lib/ppom/ppom-middleware.ts | 21 ++- app/scripts/metamask-controller.js | 1 - 3 files changed, 89 insertions(+), 73 deletions(-) diff --git a/app/scripts/lib/ppom/ppom-middleware.test.ts b/app/scripts/lib/ppom/ppom-middleware.test.ts index 857f55af5579..6b7434ea0f8c 100644 --- a/app/scripts/lib/ppom/ppom-middleware.test.ts +++ b/app/scripts/lib/ppom/ppom-middleware.test.ts @@ -8,7 +8,7 @@ import { BlockaidResultType, } from '../../../../shared/constants/security-provider'; import { flushPromises } from '../../../../test/lib/timer-helpers'; - +import { mockNetworkState } from '../../../../test/stub/networks'; import { createPPOMMiddleware, PPOMMiddlewareRequest } from './ppom-middleware'; import { generateSecurityAlertId, @@ -34,18 +34,22 @@ const REQUEST_MOCK = { params: [], id: '', jsonrpc: '2.0' as const, - origin: 'test.com', - networkClientId: 'networkClientId', }; const createMiddleware = ( options: { - chainId?: Hex; + chainId?: Hex | null; error?: Error; securityAlertsEnabled?: boolean; - } = {}, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + updateSecurityAlertResponse?: any; + } = { + updateSecurityAlertResponse: () => undefined, + }, ) => { - const { chainId, error, securityAlertsEnabled } = options; + const { chainId, error, securityAlertsEnabled, updateSecurityAlertResponse } = + options; const ppomController = {}; @@ -64,9 +68,10 @@ const createMiddleware = ( } const networkController = { - getNetworkConfigurationByNetworkClientId: jest - .fn() - .mockReturnValue({ chainId: chainId || CHAIN_IDS.MAINNET }), + state: { + ...mockNetworkState({ chainId: chainId || CHAIN_IDS.MAINNET }), + ...(chainId === null ? { providerConfig: {} } : undefined), + }, }; const appStateController = { @@ -77,9 +82,7 @@ const createMiddleware = ( listAccounts: () => [{ address: INTERNAL_ACCOUNT_ADDRESS }], }; - const updateSecurityAlertResponse = jest.fn(); - - const middleware = createPPOMMiddleware( + return createPPOMMiddleware( // TODO: Replace `any` with type // eslint-disable-next-line @typescript-eslint/no-explicit-any ppomController as any, @@ -96,16 +99,6 @@ const createMiddleware = ( accountsController as any, updateSecurityAlertResponse, ); - - return { - middleware, - ppomController, - preferenceController, - networkController, - appStateController, - accountsController, - updateSecurityAlertResponse, - }; }; describe('PPOMMiddleware', () => { @@ -132,29 +125,12 @@ describe('PPOMMiddleware', () => { }; }); - it('gets the network configuration for the request networkClientId', async () => { - const { middleware, networkController } = createMiddleware(); - - const req = { - ...REQUEST_MOCK, - method: 'eth_sendTransaction', - securityAlertResponse: undefined, - }; - - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, () => undefined); - - await flushPromises(); - - expect( - networkController.getNetworkConfigurationByNetworkClientId, - ).toHaveBeenCalledTimes(1); - expect( - networkController.getNetworkConfigurationByNetworkClientId, - ).toHaveBeenCalledWith('networkClientId'); - }); - it('updates alert response after validating request', async () => { - const { middleware, updateSecurityAlertResponse } = createMiddleware(); + const updateSecurityAlertResponse = jest.fn(); + + const middlewareFunction = createMiddleware({ + updateSecurityAlertResponse, + }); const req = { ...REQUEST_MOCK, @@ -162,7 +138,11 @@ describe('PPOMMiddleware', () => { securityAlertResponse: undefined, }; - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, () => undefined); + await middlewareFunction( + req, + { ...JsonRpcResponseStruct.TYPE }, + () => undefined, + ); await flushPromises(); @@ -175,7 +155,7 @@ describe('PPOMMiddleware', () => { }); it('adds loading response to confirmation requests while validation is in progress', async () => { - const { middleware } = createMiddleware(); + const middlewareFunction = createMiddleware(); const req: PPOMMiddlewareRequest<(string | { to: string })[]> = { ...REQUEST_MOCK, @@ -183,7 +163,11 @@ describe('PPOMMiddleware', () => { securityAlertResponse: undefined, }; - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, () => undefined); + await middlewareFunction( + req, + { ...JsonRpcResponseStruct.TYPE }, + () => undefined, + ); expect(req.securityAlertResponse?.reason).toBe(BlockaidReason.inProgress); expect(req.securityAlertResponse?.result_type).toBe( @@ -192,7 +176,7 @@ describe('PPOMMiddleware', () => { }); it('does not do validation if the user has not enabled the preference', async () => { - const { middleware } = createMiddleware({ + const middlewareFunction = createMiddleware({ securityAlertsEnabled: false, }); @@ -203,7 +187,29 @@ describe('PPOMMiddleware', () => { }; // @ts-expect-error Passing in invalid input for testing purposes - await middleware(req, undefined, () => undefined); + await middlewareFunction(req, undefined, () => undefined); + + expect(req.securityAlertResponse).toBeUndefined(); + expect(validateRequestWithPPOM).not.toHaveBeenCalled(); + }); + + it('does not do validation if unable to get the chainId from the network provider config', async () => { + isChainSupportedMock.mockResolvedValue(false); + const middlewareFunction = createMiddleware({ + chainId: null, + }); + + const req = { + ...REQUEST_MOCK, + method: 'eth_sendTransaction', + securityAlertResponse: undefined, + }; + + await middlewareFunction( + req, + { ...JsonRpcResponseStruct.TYPE }, + () => undefined, + ); expect(req.securityAlertResponse).toBeUndefined(); expect(validateRequestWithPPOM).not.toHaveBeenCalled(); @@ -211,7 +217,7 @@ describe('PPOMMiddleware', () => { it('does not do validation if user is not on a supported network', async () => { isChainSupportedMock.mockResolvedValue(false); - const { middleware } = createMiddleware({ + const middlewareFunction = createMiddleware({ chainId: '0x2', }); @@ -221,14 +227,18 @@ describe('PPOMMiddleware', () => { securityAlertResponse: undefined, }; - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, () => undefined); + await middlewareFunction( + req, + { ...JsonRpcResponseStruct.TYPE }, + () => undefined, + ); expect(req.securityAlertResponse).toBeUndefined(); expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); it('does not do validation when request is not for confirmation method', async () => { - const { middleware } = createMiddleware(); + const middlewareFunction = createMiddleware(); const req = { ...REQUEST_MOCK, @@ -236,14 +246,18 @@ describe('PPOMMiddleware', () => { securityAlertResponse: undefined, }; - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, () => undefined); + await middlewareFunction( + req, + { ...JsonRpcResponseStruct.TYPE }, + () => undefined, + ); expect(req.securityAlertResponse).toBeUndefined(); expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); it('does not do validation when request is send to users own account', async () => { - const { middleware } = createMiddleware(); + const middlewareFunction = createMiddleware(); const req = { ...REQUEST_MOCK, @@ -252,14 +266,18 @@ describe('PPOMMiddleware', () => { securityAlertResponse: undefined, }; - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, () => undefined); + await middlewareFunction( + req, + { ...JsonRpcResponseStruct.TYPE }, + () => undefined, + ); expect(req.securityAlertResponse).toBeUndefined(); expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); it('does not do validation for SIWE signature', async () => { - const { middleware } = createMiddleware({ + const middlewareFunction = createMiddleware({ securityAlertsEnabled: true, }); @@ -280,17 +298,17 @@ describe('PPOMMiddleware', () => { detectSIWEMock.mockReturnValue({ isSIWEMessage: true } as SIWEMessage); // @ts-expect-error Passing invalid input for testing purposes - await middleware(req, undefined, () => undefined); + await middlewareFunction(req, undefined, () => undefined); expect(req.securityAlertResponse).toBeUndefined(); expect(validateRequestWithPPOM).not.toHaveBeenCalled(); }); it('calls next method', async () => { - const { middleware } = createMiddleware(); + const middlewareFunction = createMiddleware(); const nextMock = jest.fn(); - await middleware( + await middlewareFunction( { ...REQUEST_MOCK, method: 'eth_sendTransaction' }, { ...JsonRpcResponseStruct.TYPE }, nextMock, @@ -305,7 +323,7 @@ describe('PPOMMiddleware', () => { const nextMock = jest.fn(); - const { middleware } = createMiddleware({ error }); + const middlewareFunction = createMiddleware({ error }); const req = { ...REQUEST_MOCK, @@ -313,7 +331,7 @@ describe('PPOMMiddleware', () => { securityAlertResponse: undefined, }; - await middleware(req, { ...JsonRpcResponseStruct.TYPE }, nextMock); + await middlewareFunction(req, { ...JsonRpcResponseStruct.TYPE }, nextMock); expect(req.securityAlertResponse).toStrictEqual( SECURITY_ALERT_RESPONSE_MOCK, diff --git a/app/scripts/lib/ppom/ppom-middleware.ts b/app/scripts/lib/ppom/ppom-middleware.ts index 5b9107337a05..1bad576e3881 100644 --- a/app/scripts/lib/ppom/ppom-middleware.ts +++ b/app/scripts/lib/ppom/ppom-middleware.ts @@ -1,9 +1,6 @@ import { AccountsController } from '@metamask/accounts-controller'; import { PPOMController } from '@metamask/ppom-validator'; -import { - NetworkClientId, - NetworkController, -} from '@metamask/network-controller'; +import { NetworkController } from '@metamask/network-controller'; import { Json, JsonRpcParams, @@ -17,6 +14,8 @@ import { SIGNING_METHODS } from '../../../../shared/constants/transaction'; import PreferencesController from '../../controllers/preferences-controller'; import { AppStateController } from '../../controllers/app-state'; import { LOADING_SECURITY_ALERT_RESPONSE } from '../../../../shared/constants/security-provider'; +// eslint-disable-next-line import/no-restricted-paths +import { getProviderConfig } from '../../../../ui/ducks/metamask/metamask'; import { trace, TraceContext, TraceName } from '../../../../shared/lib/trace'; import { generateSecurityAlertId, @@ -35,7 +34,6 @@ const CONFIRMATION_METHODS = Object.freeze([ export type PPOMMiddlewareRequest< Params extends JsonRpcParams = JsonRpcParams, > = Required> & { - networkClientId: NetworkClientId; securityAlertResponse?: SecurityAlertResponse | undefined; traceContext?: TraceContext; }; @@ -81,13 +79,14 @@ export function createPPOMMiddleware< const securityAlertsEnabled = preferencesController.store.getState()?.securityAlertsEnabled; - // This will always exist as the SelectedNetworkMiddleware - // adds networkClientId to the request before this middleware runs const { chainId } = - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - networkController.getNetworkConfigurationByNetworkClientId( - req.networkClientId, - )!; + getProviderConfig({ + metamask: networkController.state, + }) ?? {}; + if (!chainId) { + return; + } + const isSupportedChain = await isChainSupported(chainId); if ( diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 1e7bdf4a7cf0..128a415246cf 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -5545,7 +5545,6 @@ export default class MetamaskController extends EventEmitter { engine.push(createTracingMiddleware()); - // PPOMMiddleware come after the SelectedNetworkMiddleware engine.push( createPPOMMiddleware( this.ppomController, From 6e736817beb6c5d407949b47f2e5ace14b112955 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Tue, 15 Oct 2024 13:50:19 +0200 Subject: [PATCH 11/46] cherry-pick: Fix Snaps usage of PhishingController (#27833) ## **Description** Fixes two problems with Snaps usage of `PhishingController`. Following https://github.com/MetaMask/metamask-extension/pull/25839 the PhishingController expects full URLs instead of hostnames as the input to `testOrigin`. In that PR, the argument of `isOnPhishingList` was incorrectly changed. This PR also patches in some changes from the `snaps` repo that are currently blocked by a release: https://github.com/MetaMask/snaps/pull/2835, https://github.com/MetaMask/snaps/pull/2750 This PR cherry-picks a commit from `develop` that fixes this: https://github.com/MetaMask/metamask-extension/commit/1f1e142f498c96c142731cea602abd8069b2f5e0 [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27833?quickstart=1) ## **Manual testing steps** 1. Create a Snap that links to an URL blocked with `eth-phishing-detect` 2. See that triggering the Snap is disallowed if the user has phishing detection enabled --- ...ask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch | 120 ++++++++++++++++++ app/scripts/metamask-controller.js | 4 +- package.json | 5 +- yarn.lock | 39 +++++- 4 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 .yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch diff --git a/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch b/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch new file mode 100644 index 000000000000..3361025d4860 --- /dev/null +++ b/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch @@ -0,0 +1,120 @@ +diff --git a/dist/ui.cjs b/dist/ui.cjs +index 300fe9e97bba85945e3c2d200e736987453f8268..d6fa322e2b3629f41d653b91db52c3db85064276 100644 +--- a/dist/ui.cjs ++++ b/dist/ui.cjs +@@ -200,13 +200,23 @@ function getMarkdownLinks(text) { + * @param link - The link to validate. + * @param isOnPhishingList - The function that checks the link against the + * phishing list. ++ * @throws If the link is invalid. + */ + function validateLink(link, isOnPhishingList) { + try { + const url = new URL(link); + (0, utils_1.assert)(ALLOWED_PROTOCOLS.includes(url.protocol), `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`); +- const hostname = url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname; +- (0, utils_1.assert)(!isOnPhishingList(hostname), 'The specified URL is not allowed.'); ++ if (url.protocol === 'mailto:') { ++ const emails = url.pathname.split(','); ++ for (const email of emails) { ++ const hostname = email.split('@')[1]; ++ (0, utils_1.assert)(!hostname.includes(':')); ++ const href = `https://${hostname}`; ++ (0, utils_1.assert)(!isOnPhishingList(href), 'The specified URL is not allowed.'); ++ } ++ return; ++ } ++ (0, utils_1.assert)(!isOnPhishingList(url.href), 'The specified URL is not allowed.'); + } + catch (error) { + throw new Error(`Invalid URL: ${error?.code === 'ERR_ASSERTION' ? error.message : 'Unable to parse URL.'}`); +diff --git a/dist/ui.cjs.map b/dist/ui.cjs.map +index 71b5ecb9eb8bc8bdf919daccf24b25737ee69819..6d6e56cd7fea85e4d477c0399506a03d465ca740 100644 +--- a/dist/ui.cjs.map ++++ b/dist/ui.cjs.map +@@ -1 +1 @@ +-{"version":3,"file":"ui.cjs","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":";;;;AACA,mDAA+C;AAa/C,iDAiBiC;AACjC,2CAKyB;AACzB,mCAA2C;AAG3C,MAAM,eAAe,GAAG,KAAM,CAAC,CAAC,QAAQ;AACxC,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEhD;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAA6C;IACrE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,SAAS,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,aAAa,CAAC;QACvB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW,CAAO,QAAgB;IACzC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,KAAmC;IACtD,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,OAAO,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,SAAS,sBAAsB,CAAC,MAAe;IAC7C,OAAO,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB,CAAC,KAAY;IACzC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO,uBAAC,UAAI,IAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,GAAI,CAAC;QAClE,CAAC;QAED,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,IAAI,CAAC;QAEpB,KAAK,QAAQ;YACX,OAAO,CACL,uBAAC,UAAI,cAED,sBAAsB;gBACpB,0DAA0D;gBAC1D,iEAAiE;gBACjE,mCAAmC;gBACnC,KAAK,CAAC,MAAiB,CACR,GAEd,CACR,CAAC;QAEJ,KAAK,IAAI;YACP,OAAO,CACL,uBAAC,YAAM,cAEH,sBAAsB;gBACpB,0DAA0D;gBAC1D,iEAAiE;gBACjE,mCAAmC;gBACnC,KAAK,CAAC,MAAiB,CACN,GAEd,CACV,CAAC;QAEJ;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAC7B,KAAa;IAEb,MAAM,UAAU,GAAG,IAAA,cAAK,EAAC,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,MAAM,QAAQ,GACZ,EAAE,CAAC;IAEL,IAAA,mBAAU,EAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC/B,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC;YAED,MAAM,EAAE,MAAM,EAAE,GAAG,KAAyB,CAAC;YAC7C,yFAAyF;YACzF,QAAQ,CAAC,IAAI,CACX,GAAI,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAKpC,CACL,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAC5E,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,CAI7C,CAAC;AACN,CAAC;AAhCD,0CAgCC;AAED;;;;;;GAMG;AACH,SAAS,yBAAyB,CAAC,SAAoB;IACrD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAA,cAAM,EACJ,QAAQ,IAAI,eAAe,EAC3B,gDACE,eAAe,GAAG,IACpB,MAAM,CACP,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,0BAA0B,CACxC,eAA0B;IAE1B,yBAAyB,CAAC,eAAe,CAAC,CAAC;IAE3C;;;;;;OAMG;IACH,SAAS,UAAU,CAAC,SAAoB;QACtC,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;YACvB,KAAK,oBAAQ,CAAC,OAAO;gBACnB,OAAO,uBAAC,aAAO,IAAC,OAAO,EAAE,SAAS,CAAC,KAAK,GAAI,CAAC;YAE/C,KAAK,oBAAQ,CAAC,MAAM;gBAClB,OAAO,CACL,uBAAC,YAAM,IACL,IAAI,EAAE,SAAS,CAAC,IAAI,EACpB,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,OAAO,CAAC,EAC5C,IAAI,EAAE,SAAS,CAAC,UAAU,YAEzB,SAAS,CAAC,KAAK,GACT,CACV,CAAC;YAEJ,KAAK,oBAAQ,CAAC,QAAQ;gBACpB,OAAO,CACL,uBAAC,cAAQ,IAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,GAAI,CACrE,CAAC;YAEJ,KAAK,oBAAQ,CAAC,OAAO;gBACnB,OAAO,uBAAC,aAAO,KAAG,CAAC;YAErB,KAAK,oBAAQ,CAAC,IAAI;gBAChB,OAAO,CACL,uBAAC,UAAI,IAAC,IAAI,EAAE,SAAS,CAAC,IAAI,YACvB,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAC3C,CACR,CAAC;YAEJ,KAAK,oBAAQ,CAAC,OAAO;gBACnB,OAAO,uBAAC,aAAO,IAAC,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAI,CAAC;YAEhD,KAAK,oBAAQ,CAAC,KAAK;gBACjB,qEAAqE;gBACrE,OAAO,uBAAC,WAAK,IAAC,GAAG,EAAE,SAAS,CAAC,KAAK,GAAI,CAAC;YAEzC,KAAK,oBAAQ,CAAC,KAAK;gBACjB,OAAO,CACL,uBAAC,WAAK,IAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,YACnD,uBAAC,WAAK,IACJ,IAAI,EAAE,SAAS,CAAC,IAAI,EACpB,IAAI,EAAE,SAAS,CAAC,SAAS,EACzB,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,WAAW,EAAE,SAAS,CAAC,WAAW,GAClC,GACI,CACT,CAAC;YAEJ,KAAK,oBAAQ,CAAC,KAAK;gBACjB,sCAAsC;gBACtC,OAAO,CACL,uBAAC,SAAG,IAAC,QAAQ,EAAE,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAI,CACnE,CAAC;YAEJ,KAAK,oBAAQ,CAAC,GAAG;gBACf,OAAO,CACL,uBAAC,SAAG,IAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,YACpD,UAAU,CAAC,SAAS,CAAC,KAAK,CAAgB,GACvC,CACP,CAAC;YAEJ,KAAK,oBAAQ,CAAC,OAAO;gBACnB,OAAO,uBAAC,aAAO,KAAG,CAAC;YAErB,KAAK,oBAAQ,CAAC,IAAI;gBAChB,OAAO,uBAAC,UAAI,cAAE,WAAW,CAAC,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,GAAQ,CAAC;YAEtE,4BAA4B;YAC5B;gBACE,OAAO,IAAA,wBAAgB,EAAC,SAAS,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC,eAAe,CAAC,CAAC;AACrC,CAAC;AAxFD,gEAwFC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,MAAM,GAAG,IAAA,cAAK,EAAC,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAkB,EAAE,CAAC;IAEhC,oDAAoD;IACpD,IAAA,mBAAU,EAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,KAAoB,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAC1B,IAAY,EACZ,gBAA0C;IAE1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAA,cAAM,EACJ,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EACxC,4BAA4B,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5D,CAAC;QAEF,MAAM,QAAQ,GACZ,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;QAEzE,IAAA,cAAM,EAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,mCAAmC,CAAC,CAAC;IAC3E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,gBACE,KAAK,EAAE,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,sBACpD,EAAE,CACH,CAAC;IACJ,CAAC;AACH,CAAC;AAtBD,oCAsBC;AAED;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,IAAY,EACZ,gBAA0C;IAE1C,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AATD,8CASC;AAED;;;;;;;GAOG;AACH,SAAgB,gBAAgB,CAC9B,IAAgB,EAChB,gBAA0C;IAE1C,OAAO,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,EAAE;QAC1B,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC;AAXD,4CAWC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,SAAoB;IACrD,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC;IAE3B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,oBAAQ,CAAC,KAAK;YACjB,OAAO,SAAS,CAAC,QAAQ,CAAC,MAAM;YAC9B,oFAAoF;YACpF,qEAAqE;YACrE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,EAC7C,CAAC,CACF,CAAC;QAEJ,KAAK,oBAAQ,CAAC,GAAG;YACf,OAAO,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAE7C,KAAK,oBAAQ,CAAC,IAAI;YAChB,OAAO,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QAEhC;YACE,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC;AArBD,gDAqBC;AAED;;;;;GAKG;AACH,SAAgB,WAAW,CACzB,OAAgB;IAIhB,OAAO,IAAA,mBAAW,EAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAChD,CAAC;AAND,kCAMC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,KAA2C;IACjE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,OAAmB;IAChD,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1C,uEAAuE;YACvE,2DAA2D;YAC3D,OAAO,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3B,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAdD,wCAcC;AAED;;;;;;;GAOG;AACH,SAAgB,OAAO,CACrB,IAA+B,EAC/B,QAAgE,EAChE,KAAK,GAAG,CAAC;IAET,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAmB,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YAClE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,WAAW,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IACE,IAAA,mBAAW,EAAC,IAAI,EAAE,OAAO,CAAC;QAC1B,IAAA,qBAAa,EAAC,IAAI,CAAC,KAAK,CAAC;QACzB,IAAA,mBAAW,EAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,EACnC,CAAC;QACD,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,IAAA,qBAAa,EAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;gBACxD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC9B,OAAO,WAAW,CAAC;gBACrB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAtCD,0BAsCC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,IAAa;IAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,IAAI,GAAG,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,KAA8B;IACpD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SACzB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,UAAU,CAAC;SACrC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;SACxD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,IAAc,EAAE,WAAW,GAAG,CAAC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACxC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,GAAG,MAAM,GAAG,IAAI,IAAI,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAA0B,CAAC;IACnD,MAAM,eAAe,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpD,IAAI,IAAA,mBAAW,EAAC,KAAK,EAAE,UAAU,CAAC,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,QAAoB,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC;QAC3E,OAAO,GAAG,MAAM,IAAI,IAAI,GAAG,cAAc,CACvC,KAAK,CACN,MAAM,QAAQ,GAAG,MAAM,KAAK,IAAI,IAAI,eAAe,EAAE,CAAC;IACzD,CAAC;IAED,OAAO,GAAG,MAAM,IAAI,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,eAAe,EAAE,CAAC;AAC1E,CAAC;AAzBD,oCAyBC","sourcesContent":["import type { Component } from '@metamask/snaps-sdk';\nimport { NodeType } from '@metamask/snaps-sdk';\nimport type {\n BoldChildren,\n GenericSnapElement,\n ItalicChildren,\n JSXElement,\n LinkElement,\n Nestable,\n RowChildren,\n SnapNode,\n StandardFormattingElement,\n TextChildren,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n Italic,\n Link,\n Bold,\n Row,\n Text,\n Field,\n Image,\n Input,\n Heading,\n Form,\n Divider,\n Spinner,\n Copyable,\n Box,\n Button,\n Address,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n assert,\n assertExhaustive,\n hasProperty,\n isPlainObject,\n} from '@metamask/utils';\nimport { lexer, walkTokens } from 'marked';\nimport type { Token, Tokens } from 'marked';\n\nconst MAX_TEXT_LENGTH = 50_000; // 50 kb\nconst ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n\n/**\n * Get the button variant from a legacy button component variant.\n *\n * @param variant - The legacy button component variant.\n * @returns The button variant.\n */\nfunction getButtonVariant(variant?: 'primary' | 'secondary' | undefined) {\n switch (variant) {\n case 'primary':\n return 'primary';\n case 'secondary':\n return 'destructive';\n default:\n return undefined;\n }\n}\n\n/**\n * Get the children of a JSX element. If there is only one child, the child is\n * returned directly. Otherwise, the children are returned as an array.\n *\n * @param elements - The JSX elements.\n * @returns The child or children.\n */\nfunction getChildren(elements: Type[]) {\n if (elements.length === 1) {\n return elements[0];\n }\n\n return elements;\n}\n\n/**\n * Get the text of a link token.\n *\n * @param token - The link token.\n * @returns The text of the link token.\n */\nfunction getLinkText(token: Tokens.Link | Tokens.Generic) {\n if (token.tokens && token.tokens.length > 0) {\n return getChildren(token.tokens.flatMap(getTextChildFromToken));\n }\n\n return token.href;\n}\n\n/**\n * Get the text child from a list of markdown tokens.\n *\n * @param tokens - The markdown tokens.\n * @returns The text child.\n */\nfunction getTextChildFromTokens(tokens: Token[]) {\n return getChildren(tokens.flatMap(getTextChildFromToken));\n}\n\n/**\n * Get the text child from a markdown token.\n *\n * @param token - The markdown token.\n * @returns The text child.\n */\nfunction getTextChildFromToken(token: Token): TextChildren {\n switch (token.type) {\n case 'link': {\n return ;\n }\n\n case 'text':\n return token.text;\n\n case 'strong':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as BoldChildren\n }\n \n );\n\n case 'em':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as ItalicChildren\n }\n \n );\n\n default:\n return null;\n }\n}\n\n/**\n * Get all text children from a markdown string.\n *\n * @param value - The markdown string.\n * @returns The text children.\n */\nexport function getTextChildren(\n value: string,\n): (string | StandardFormattingElement | LinkElement)[] {\n const rootTokens = lexer(value, { gfm: false });\n const children: (string | StandardFormattingElement | LinkElement | null)[] =\n [];\n\n walkTokens(rootTokens, (token) => {\n if (token.type === 'paragraph') {\n if (children.length > 0) {\n children.push('\\n\\n');\n }\n\n const { tokens } = token as Tokens.Paragraph;\n // We do not need to consider nesting deeper than 1 level here and we can therefore cast.\n children.push(\n ...(tokens.flatMap(getTextChildFromToken) as (\n | string\n | StandardFormattingElement\n | LinkElement\n | null\n )[]),\n );\n }\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n return children.filter((child) => child !== null) as (\n | string\n | StandardFormattingElement\n | LinkElement\n )[];\n}\n\n/**\n * Validate the text size of a component. The text size is the total length of\n * all text in the component.\n *\n * @param component - The component to validate.\n * @throws An error if the text size exceeds the maximum allowed size.\n */\nfunction validateComponentTextSize(component: Component) {\n const textSize = getTotalTextLength(component);\n assert(\n textSize <= MAX_TEXT_LENGTH,\n `The text in a Snap UI may not be larger than ${\n MAX_TEXT_LENGTH / 1000\n } kB.`,\n );\n}\n\n/**\n * Get a JSX element from a legacy UI component. This supports all legacy UI\n * components, and maps them to their JSX equivalents where possible.\n *\n * This function validates the text size of the component, but does not validate\n * the total size. The total size of the component should be validated before\n * calling this function.\n *\n * @param legacyComponent - The legacy UI component.\n * @returns The JSX element.\n */\nexport function getJsxElementFromComponent(\n legacyComponent: Component,\n): JSXElement {\n validateComponentTextSize(legacyComponent);\n\n /**\n * Get the JSX element for a component. This function is recursive and will\n * call itself for child components.\n *\n * @param component - The component to convert to a JSX element.\n * @returns The JSX element.\n */\n function getElement(component: Component) {\n switch (component.type) {\n case NodeType.Address:\n return
;\n\n case NodeType.Button:\n return (\n \n {component.value}\n \n );\n\n case NodeType.Copyable:\n return (\n \n );\n\n case NodeType.Divider:\n return ;\n\n case NodeType.Form:\n return (\n
\n {getChildren(component.children.map(getElement))}\n
\n );\n\n case NodeType.Heading:\n return ;\n\n case NodeType.Image:\n // `Image` supports `alt`, but the legacy `Image` component does not.\n return ;\n\n case NodeType.Input:\n return (\n \n \n \n );\n\n case NodeType.Panel:\n // `Panel` is renamed to `Box` in JSX.\n return (\n \n );\n\n case NodeType.Row:\n return (\n \n {getElement(component.value) as RowChildren}\n \n );\n\n case NodeType.Spinner:\n return ;\n\n case NodeType.Text:\n return {getChildren(getTextChildren(component.value))};\n\n /* istanbul ignore next 2 */\n default:\n return assertExhaustive(component);\n }\n }\n\n return getElement(legacyComponent);\n}\n\n/**\n * Extract all links from a Markdown text string using the `marked` lexer.\n *\n * @param text - The markdown text string.\n * @returns A list of URLs linked to in the string.\n */\nfunction getMarkdownLinks(text: string) {\n const tokens = lexer(text, { gfm: false });\n const links: Tokens.Link[] = [];\n\n // Walk the lexed tokens and collect all link tokens\n walkTokens(tokens, (token) => {\n if (token.type === 'link') {\n links.push(token as Tokens.Link);\n }\n });\n\n return links;\n}\n\n/**\n * Validate a link against the phishing list.\n *\n * @param link - The link to validate.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n */\nexport function validateLink(\n link: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n try {\n const url = new URL(link);\n assert(\n ALLOWED_PROTOCOLS.includes(url.protocol),\n `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,\n );\n\n const hostname =\n url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname;\n\n assert(!isOnPhishingList(hostname), 'The specified URL is not allowed.');\n } catch (error) {\n throw new Error(\n `Invalid URL: ${\n error?.code === 'ERR_ASSERTION' ? error.message : 'Unable to parse URL.'\n }`,\n );\n }\n}\n\n/**\n * Search for Markdown links in a string and checks them against the phishing\n * list.\n *\n * @param text - The text to verify.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the text contains a link that is not allowed.\n */\nexport function validateTextLinks(\n text: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n const links = getMarkdownLinks(text);\n\n for (const link of links) {\n validateLink(link.href, isOnPhishingList);\n }\n}\n\n/**\n * Walk a JSX tree and validate each {@link LinkElement} node against the\n * phishing list.\n *\n * @param node - The JSX node to walk.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n */\nexport function validateJsxLinks(\n node: JSXElement,\n isOnPhishingList: (url: string) => boolean,\n) {\n walkJsx(node, (childNode) => {\n if (childNode.type !== 'Link') {\n return;\n }\n\n validateLink(childNode.props.href, isOnPhishingList);\n });\n}\n\n/**\n * Calculate the total length of all text in the component.\n *\n * @param component - A custom UI component.\n * @returns The total length of all text components in the component.\n */\nexport function getTotalTextLength(component: Component): number {\n const { type } = component;\n\n switch (type) {\n case NodeType.Panel:\n return component.children.reduce(\n // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n (sum, node) => sum + getTotalTextLength(node),\n 0,\n );\n\n case NodeType.Row:\n return getTotalTextLength(component.value);\n\n case NodeType.Text:\n return component.value.length;\n\n default:\n return 0;\n }\n}\n\n/**\n * Check if a JSX element has children.\n *\n * @param element - A JSX element.\n * @returns `true` if the element has children, `false` otherwise.\n */\nexport function hasChildren(\n element: Element,\n): element is Element & {\n props: { children: Nestable };\n} {\n return hasProperty(element.props, 'children');\n}\n\n/**\n * Filter a JSX child to remove `null`, `undefined`, plain booleans, and empty\n * strings.\n *\n * @param child - The JSX child to filter.\n * @returns `true` if the child is not `null`, `undefined`, a plain boolean, or\n * an empty string, `false` otherwise.\n */\nfunction filterJsxChild(child: JSXElement | string | boolean | null): boolean {\n return Boolean(child) && child !== true;\n}\n\n/**\n * Get the children of a JSX element as an array. If the element has only one\n * child, the child is returned as an array.\n *\n * @param element - A JSX element.\n * @returns The children of the element.\n */\nexport function getJsxChildren(element: JSXElement): (JSXElement | string)[] {\n if (hasChildren(element)) {\n if (Array.isArray(element.props.children)) {\n // @ts-expect-error - Each member of the union type has signatures, but\n // none of those signatures are compatible with each other.\n return element.props.children.filter(filterJsxChild).flat(Infinity);\n }\n\n if (element.props.children) {\n return [element.props.children];\n }\n }\n\n return [];\n}\n\n/**\n * Walk a JSX tree and call a callback on each node.\n *\n * @param node - The JSX node to walk.\n * @param callback - The callback to call on each node.\n * @param depth - The current depth in the JSX tree for a walk.\n * @returns The result of the callback, if any.\n */\nexport function walkJsx(\n node: JSXElement | JSXElement[],\n callback: (node: JSXElement, depth: number) => Value | undefined,\n depth = 0,\n): Value | undefined {\n if (Array.isArray(node)) {\n for (const child of node) {\n const childResult = walkJsx(child as JSXElement, callback, depth);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n\n return undefined;\n }\n\n const result = callback(node, depth);\n if (result !== undefined) {\n return result;\n }\n\n if (\n hasProperty(node, 'props') &&\n isPlainObject(node.props) &&\n hasProperty(node.props, 'children')\n ) {\n const children = getJsxChildren(node);\n for (const child of children) {\n if (isPlainObject(child)) {\n const childResult = walkJsx(child, callback, depth + 1);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Serialise a JSX prop to a string.\n *\n * @param prop - The JSX prop.\n * @returns The serialised JSX prop.\n */\nfunction serialiseProp(prop: unknown): string {\n if (typeof prop === 'string') {\n return `\"${prop}\"`;\n }\n\n return `{${JSON.stringify(prop)}}`;\n}\n\n/**\n * Serialise JSX props to a string.\n *\n * @param props - The JSX props.\n * @returns The serialised JSX props.\n */\nfunction serialiseProps(props: Record): string {\n return Object.entries(props)\n .filter(([key]) => key !== 'children')\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => ` ${key}=${serialiseProp(value)}`)\n .join('');\n}\n\n/**\n * Serialise a JSX node to a string.\n *\n * @param node - The JSX node.\n * @param indentation - The indentation level. Defaults to `0`. This should not\n * be set by the caller, as it is used for recursion.\n * @returns The serialised JSX node.\n */\nexport function serialiseJsx(node: SnapNode, indentation = 0): string {\n if (Array.isArray(node)) {\n return node.map((child) => serialiseJsx(child, indentation)).join('');\n }\n\n const indent = ' '.repeat(indentation);\n if (typeof node === 'string') {\n return `${indent}${node}\\n`;\n }\n\n if (!node) {\n return '';\n }\n\n const { type, props } = node as GenericSnapElement;\n const trailingNewline = indentation > 0 ? '\\n' : '';\n\n if (hasProperty(props, 'children')) {\n const children = serialiseJsx(props.children as SnapNode, indentation + 1);\n return `${indent}<${type}${serialiseProps(\n props,\n )}>\\n${children}${indent}${trailingNewline}`;\n }\n\n return `${indent}<${type}${serialiseProps(props)} />${trailingNewline}`;\n}\n"]} +\ No newline at end of file ++{"version":3,"file":"ui.cjs","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from '@metamask/snaps-sdk';\nimport { NodeType } from '@metamask/snaps-sdk';\nimport type {\n BoldChildren,\n GenericSnapElement,\n ItalicChildren,\n JSXElement,\n LinkElement,\n Nestable,\n RowChildren,\n SnapNode,\n StandardFormattingElement,\n TextChildren,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n Italic,\n Link,\n Bold,\n Row,\n Text,\n Field,\n Image,\n Input,\n Heading,\n Form,\n Divider,\n Spinner,\n Copyable,\n Box,\n Button,\n Address,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n assert,\n assertExhaustive,\n hasProperty,\n isPlainObject,\n} from '@metamask/utils';\nimport { lexer, walkTokens } from 'marked';\nimport type { Token, Tokens } from 'marked';\n\nconst MAX_TEXT_LENGTH = 50_000; // 50 kb\nconst ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n\n/**\n * Get the button variant from a legacy button component variant.\n *\n * @param variant - The legacy button component variant.\n * @returns The button variant.\n */\nfunction getButtonVariant(variant?: 'primary' | 'secondary' | undefined) {\n switch (variant) {\n case 'primary':\n return 'primary';\n case 'secondary':\n return 'destructive';\n default:\n return undefined;\n }\n}\n\n/**\n * Get the children of a JSX element. If there is only one child, the child is\n * returned directly. Otherwise, the children are returned as an array.\n *\n * @param elements - The JSX elements.\n * @returns The child or children.\n */\nfunction getChildren(elements: Type[]) {\n if (elements.length === 1) {\n return elements[0];\n }\n\n return elements;\n}\n\n/**\n * Get the text of a link token.\n *\n * @param token - The link token.\n * @returns The text of the link token.\n */\nfunction getLinkText(token: Tokens.Link | Tokens.Generic) {\n if (token.tokens && token.tokens.length > 0) {\n return getChildren(token.tokens.flatMap(getTextChildFromToken));\n }\n\n return token.href;\n}\n\n/**\n * Get the text child from a list of markdown tokens.\n *\n * @param tokens - The markdown tokens.\n * @returns The text child.\n */\nfunction getTextChildFromTokens(tokens: Token[]) {\n return getChildren(tokens.flatMap(getTextChildFromToken));\n}\n\n/**\n * Get the text child from a markdown token.\n *\n * @param token - The markdown token.\n * @returns The text child.\n */\nfunction getTextChildFromToken(token: Token): TextChildren {\n switch (token.type) {\n case 'link': {\n return ;\n }\n\n case 'text':\n return token.text;\n\n case 'strong':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as BoldChildren\n }\n \n );\n\n case 'em':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as ItalicChildren\n }\n \n );\n\n default:\n return null;\n }\n}\n\n/**\n * Get all text children from a markdown string.\n *\n * @param value - The markdown string.\n * @returns The text children.\n */\nexport function getTextChildren(\n value: string,\n): (string | StandardFormattingElement | LinkElement)[] {\n const rootTokens = lexer(value, { gfm: false });\n const children: (string | StandardFormattingElement | LinkElement | null)[] =\n [];\n\n walkTokens(rootTokens, (token) => {\n if (token.type === 'paragraph') {\n if (children.length > 0) {\n children.push('\\n\\n');\n }\n\n const { tokens } = token as Tokens.Paragraph;\n // We do not need to consider nesting deeper than 1 level here and we can therefore cast.\n children.push(\n ...(tokens.flatMap(getTextChildFromToken) as (\n | string\n | StandardFormattingElement\n | LinkElement\n | null\n )[]),\n );\n }\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n return children.filter((child) => child !== null) as (\n | string\n | StandardFormattingElement\n | LinkElement\n )[];\n}\n\n/**\n * Validate the text size of a component. The text size is the total length of\n * all text in the component.\n *\n * @param component - The component to validate.\n * @throws An error if the text size exceeds the maximum allowed size.\n */\nfunction validateComponentTextSize(component: Component) {\n const textSize = getTotalTextLength(component);\n assert(\n textSize <= MAX_TEXT_LENGTH,\n `The text in a Snap UI may not be larger than ${\n MAX_TEXT_LENGTH / 1000\n } kB.`,\n );\n}\n\n/**\n * Get a JSX element from a legacy UI component. This supports all legacy UI\n * components, and maps them to their JSX equivalents where possible.\n *\n * This function validates the text size of the component, but does not validate\n * the total size. The total size of the component should be validated before\n * calling this function.\n *\n * @param legacyComponent - The legacy UI component.\n * @returns The JSX element.\n */\nexport function getJsxElementFromComponent(\n legacyComponent: Component,\n): JSXElement {\n validateComponentTextSize(legacyComponent);\n\n /**\n * Get the JSX element for a component. This function is recursive and will\n * call itself for child components.\n *\n * @param component - The component to convert to a JSX element.\n * @returns The JSX element.\n */\n function getElement(component: Component) {\n switch (component.type) {\n case NodeType.Address:\n return
;\n\n case NodeType.Button:\n return (\n \n {component.value}\n \n );\n\n case NodeType.Copyable:\n return (\n \n );\n\n case NodeType.Divider:\n return ;\n\n case NodeType.Form:\n return (\n
\n {getChildren(component.children.map(getElement))}\n
\n );\n\n case NodeType.Heading:\n return ;\n\n case NodeType.Image:\n // `Image` supports `alt`, but the legacy `Image` component does not.\n return ;\n\n case NodeType.Input:\n return (\n \n \n \n );\n\n case NodeType.Panel:\n // `Panel` is renamed to `Box` in JSX.\n return (\n \n );\n\n case NodeType.Row:\n return (\n \n {getElement(component.value) as RowChildren}\n \n );\n\n case NodeType.Spinner:\n return ;\n\n case NodeType.Text:\n return {getChildren(getTextChildren(component.value))};\n\n /* istanbul ignore next 2 */\n default:\n return assertExhaustive(component);\n }\n }\n\n return getElement(legacyComponent);\n}\n\n/**\n * Extract all links from a Markdown text string using the `marked` lexer.\n *\n * @param text - The markdown text string.\n * @returns A list of URLs linked to in the string.\n */\nfunction getMarkdownLinks(text: string) {\n const tokens = lexer(text, { gfm: false });\n const links: Tokens.Link[] = [];\n\n // Walk the lexed tokens and collect all link tokens\n walkTokens(tokens, (token) => {\n if (token.type === 'link') {\n links.push(token as Tokens.Link);\n }\n });\n\n return links;\n}\n\n/**\n * Validate a link against the phishing list.\n *\n * @param link - The link to validate.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the link is invalid.\n */\nexport function validateLink(\n link: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n try {\n const url = new URL(link);\n assert(\n ALLOWED_PROTOCOLS.includes(url.protocol),\n `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,\n );\n\n if (url.protocol === 'mailto:') {\n const emails = url.pathname.split(',');\n for (const email of emails) {\n const hostname = email.split('@')[1];\n assert(!hostname.includes(':'));\n const href = `https://${hostname}`;\n assert(!isOnPhishingList(href), 'The specified URL is not allowed.');\n }\n\n return;\n }\n\n assert(!isOnPhishingList(url.href), 'The specified URL is not allowed.');\n } catch (error) {\n throw new Error(\n `Invalid URL: ${\n error?.code === 'ERR_ASSERTION' ? error.message : 'Unable to parse URL.'\n }`,\n );\n }\n}\n\n/**\n * Search for Markdown links in a string and checks them against the phishing\n * list.\n *\n * @param text - The text to verify.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the text contains a link that is not allowed.\n */\nexport function validateTextLinks(\n text: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n const links = getMarkdownLinks(text);\n\n for (const link of links) {\n validateLink(link.href, isOnPhishingList);\n }\n}\n\n/**\n * Walk a JSX tree and validate each {@link LinkElement} node against the\n * phishing list.\n *\n * @param node - The JSX node to walk.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n */\nexport function validateJsxLinks(\n node: JSXElement,\n isOnPhishingList: (url: string) => boolean,\n) {\n walkJsx(node, (childNode) => {\n if (childNode.type !== 'Link') {\n return;\n }\n\n validateLink(childNode.props.href, isOnPhishingList);\n });\n}\n\n/**\n * Calculate the total length of all text in the component.\n *\n * @param component - A custom UI component.\n * @returns The total length of all text components in the component.\n */\nexport function getTotalTextLength(component: Component): number {\n const { type } = component;\n\n switch (type) {\n case NodeType.Panel:\n return component.children.reduce(\n // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n (sum, node) => sum + getTotalTextLength(node),\n 0,\n );\n\n case NodeType.Row:\n return getTotalTextLength(component.value);\n\n case NodeType.Text:\n return component.value.length;\n\n default:\n return 0;\n }\n}\n\n/**\n * Check if a JSX element has children.\n *\n * @param element - A JSX element.\n * @returns `true` if the element has children, `false` otherwise.\n */\nexport function hasChildren(\n element: Element,\n): element is Element & {\n props: { children: Nestable };\n} {\n return hasProperty(element.props, 'children');\n}\n\n/**\n * Filter a JSX child to remove `null`, `undefined`, plain booleans, and empty\n * strings.\n *\n * @param child - The JSX child to filter.\n * @returns `true` if the child is not `null`, `undefined`, a plain boolean, or\n * an empty string, `false` otherwise.\n */\nfunction filterJsxChild(child: JSXElement | string | boolean | null): boolean {\n return Boolean(child) && child !== true;\n}\n\n/**\n * Get the children of a JSX element as an array. If the element has only one\n * child, the child is returned as an array.\n *\n * @param element - A JSX element.\n * @returns The children of the element.\n */\nexport function getJsxChildren(element: JSXElement): (JSXElement | string)[] {\n if (hasChildren(element)) {\n if (Array.isArray(element.props.children)) {\n // @ts-expect-error - Each member of the union type has signatures, but\n // none of those signatures are compatible with each other.\n return element.props.children.filter(filterJsxChild).flat(Infinity);\n }\n\n if (element.props.children) {\n return [element.props.children];\n }\n }\n\n return [];\n}\n\n/**\n * Walk a JSX tree and call a callback on each node.\n *\n * @param node - The JSX node to walk.\n * @param callback - The callback to call on each node.\n * @param depth - The current depth in the JSX tree for a walk.\n * @returns The result of the callback, if any.\n */\nexport function walkJsx(\n node: JSXElement | JSXElement[],\n callback: (node: JSXElement, depth: number) => Value | undefined,\n depth = 0,\n): Value | undefined {\n if (Array.isArray(node)) {\n for (const child of node) {\n const childResult = walkJsx(child as JSXElement, callback, depth);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n\n return undefined;\n }\n\n const result = callback(node, depth);\n if (result !== undefined) {\n return result;\n }\n\n if (\n hasProperty(node, 'props') &&\n isPlainObject(node.props) &&\n hasProperty(node.props, 'children')\n ) {\n const children = getJsxChildren(node);\n for (const child of children) {\n if (isPlainObject(child)) {\n const childResult = walkJsx(child, callback, depth + 1);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Serialise a JSX prop to a string.\n *\n * @param prop - The JSX prop.\n * @returns The serialised JSX prop.\n */\nfunction serialiseProp(prop: unknown): string {\n if (typeof prop === 'string') {\n return `\"${prop}\"`;\n }\n\n return `{${JSON.stringify(prop)}}`;\n}\n\n/**\n * Serialise JSX props to a string.\n *\n * @param props - The JSX props.\n * @returns The serialised JSX props.\n */\nfunction serialiseProps(props: Record): string {\n return Object.entries(props)\n .filter(([key]) => key !== 'children')\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => ` ${key}=${serialiseProp(value)}`)\n .join('');\n}\n\n/**\n * Serialise a JSX node to a string.\n *\n * @param node - The JSX node.\n * @param indentation - The indentation level. Defaults to `0`. This should not\n * be set by the caller, as it is used for recursion.\n * @returns The serialised JSX node.\n */\nexport function serialiseJsx(node: SnapNode, indentation = 0): string {\n if (Array.isArray(node)) {\n return node.map((child) => serialiseJsx(child, indentation)).join('');\n }\n\n const indent = ' '.repeat(indentation);\n if (typeof node === 'string') {\n return `${indent}${node}\\n`;\n }\n\n if (!node) {\n return '';\n }\n\n const { type, props } = node as GenericSnapElement;\n const trailingNewline = indentation > 0 ? '\\n' : '';\n\n if (hasProperty(props, 'children')) {\n const children = serialiseJsx(props.children as SnapNode, indentation + 1);\n return `${indent}<${type}${serialiseProps(\n props,\n )}>\\n${children}${indent}${trailingNewline}`;\n }\n\n return `${indent}<${type}${serialiseProps(props)} />${trailingNewline}`;\n}\n"]} +\ No newline at end of file +diff --git a/dist/ui.d.cts b/dist/ui.d.cts +index c9bd215bf861b83df1d9b63acd586d71a37d896f..b7e6a58104694f96ac1f1608492fe71182a1c15f 100644 +--- a/dist/ui.d.cts ++++ b/dist/ui.d.cts +@@ -25,6 +25,7 @@ export declare function getJsxElementFromComponent(legacyComponent: Component): + * @param link - The link to validate. + * @param isOnPhishingList - The function that checks the link against the + * phishing list. ++ * @throws If the link is invalid. + */ + export declare function validateLink(link: string, isOnPhishingList: (url: string) => boolean): void; + /** +diff --git a/dist/ui.d.cts.map b/dist/ui.d.cts.map +index 7c6a6f95c8aa97d0e048e32d4f76c46a0cd7bd15..66fa95b636d7dc2e8d467e129dccc410b9b27b8a 100644 +--- a/dist/ui.d.cts.map ++++ b/dist/ui.d.cts.map +@@ -1 +1 @@ +-{"version":3,"file":"ui.d.cts","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAIV,UAAU,EACV,WAAW,EACX,QAAQ,EAER,QAAQ,EACR,yBAAyB,EAE1B,gCAAgC;AAuIjC;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GACZ,CAAC,MAAM,GAAG,yBAAyB,GAAG,WAAW,CAAC,EAAE,CA8BtD;AAmBD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,SAAS,GACzB,UAAU,CAsFZ;AAsBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAoB3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAS3C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAqB/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,UAAU,EACpD,OAAO,EAAE,OAAO,GACf,OAAO,IAAI,OAAO,GAAG;IACtB,KAAK,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAEA;AAcD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,CAc3E;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAC3B,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,EAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,EAChE,KAAK,SAAI,GACR,KAAK,GAAG,SAAS,CAkCnB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,SAAI,GAAG,MAAM,CAyBpE"} +\ No newline at end of file ++{"version":3,"file":"ui.d.cts","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAIV,UAAU,EACV,WAAW,EACX,QAAQ,EAER,QAAQ,EACR,yBAAyB,EAE1B,gCAAgC;AAuIjC;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GACZ,CAAC,MAAM,GAAG,yBAAyB,GAAG,WAAW,CAAC,EAAE,CA8BtD;AAmBD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,SAAS,GACzB,UAAU,CAsFZ;AAsBD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QA6B3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAS3C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAqB/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,UAAU,EACpD,OAAO,EAAE,OAAO,GACf,OAAO,IAAI,OAAO,GAAG;IACtB,KAAK,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAEA;AAcD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,CAc3E;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAC3B,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,EAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,EAChE,KAAK,SAAI,GACR,KAAK,GAAG,SAAS,CAkCnB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,SAAI,GAAG,MAAM,CAyBpE"} +\ No newline at end of file +diff --git a/dist/ui.d.mts b/dist/ui.d.mts +index 9047d932564925a86e7b82a09b17c72aee1273fe..a34aa56c5cdd8fcb7022cebbb036665a180c3d05 100644 +--- a/dist/ui.d.mts ++++ b/dist/ui.d.mts +@@ -25,6 +25,7 @@ export declare function getJsxElementFromComponent(legacyComponent: Component): + * @param link - The link to validate. + * @param isOnPhishingList - The function that checks the link against the + * phishing list. ++ * @throws If the link is invalid. + */ + export declare function validateLink(link: string, isOnPhishingList: (url: string) => boolean): void; + /** +diff --git a/dist/ui.d.mts.map b/dist/ui.d.mts.map +index e2a961017b4f1cf120155b371776653e1a1d9d0b..d551ff82192402da07af285050ca4d5cf0c258ed 100644 +--- a/dist/ui.d.mts.map ++++ b/dist/ui.d.mts.map +@@ -1 +1 @@ +-{"version":3,"file":"ui.d.mts","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAIV,UAAU,EACV,WAAW,EACX,QAAQ,EAER,QAAQ,EACR,yBAAyB,EAE1B,gCAAgC;AAuIjC;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GACZ,CAAC,MAAM,GAAG,yBAAyB,GAAG,WAAW,CAAC,EAAE,CA8BtD;AAmBD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,SAAS,GACzB,UAAU,CAsFZ;AAsBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAoB3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAS3C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAqB/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,UAAU,EACpD,OAAO,EAAE,OAAO,GACf,OAAO,IAAI,OAAO,GAAG;IACtB,KAAK,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAEA;AAcD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,CAc3E;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAC3B,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,EAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,EAChE,KAAK,SAAI,GACR,KAAK,GAAG,SAAS,CAkCnB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,SAAI,GAAG,MAAM,CAyBpE"} +\ No newline at end of file ++{"version":3,"file":"ui.d.mts","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAIV,UAAU,EACV,WAAW,EACX,QAAQ,EAER,QAAQ,EACR,yBAAyB,EAE1B,gCAAgC;AAuIjC;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,GACZ,CAAC,MAAM,GAAG,yBAAyB,GAAG,WAAW,CAAC,EAAE,CA8BtD;AAmBD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,SAAS,GACzB,UAAU,CAsFZ;AAsBD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QA6B3C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,EAChB,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,QAS3C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAqB/D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAS,UAAU,EACpD,OAAO,EAAE,OAAO,GACf,OAAO,IAAI,OAAO,GAAG;IACtB,KAAK,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,CAAA;KAAE,CAAC;CACpD,CAEA;AAcD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,CAc3E;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAC3B,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,EAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,EAChE,KAAK,SAAI,GACR,KAAK,GAAG,SAAS,CAkCnB;AA8BD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,SAAI,GAAG,MAAM,CAyBpE"} +\ No newline at end of file +diff --git a/dist/ui.mjs b/dist/ui.mjs +index 11b2b5625df002c0962216a06f258869ba65e06b..7499feea1cd9df0d90d2756741bc8e035200506f 100644 +--- a/dist/ui.mjs ++++ b/dist/ui.mjs +@@ -195,13 +195,23 @@ function getMarkdownLinks(text) { + * @param link - The link to validate. + * @param isOnPhishingList - The function that checks the link against the + * phishing list. ++ * @throws If the link is invalid. + */ + export function validateLink(link, isOnPhishingList) { + try { + const url = new URL(link); + assert(ALLOWED_PROTOCOLS.includes(url.protocol), `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`); +- const hostname = url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname; +- assert(!isOnPhishingList(hostname), 'The specified URL is not allowed.'); ++ if (url.protocol === 'mailto:') { ++ const emails = url.pathname.split(','); ++ for (const email of emails) { ++ const hostname = email.split('@')[1]; ++ assert(!hostname.includes(':')); ++ const href = `https://${hostname}`; ++ assert(!isOnPhishingList(href), 'The specified URL is not allowed.'); ++ } ++ return; ++ } ++ assert(!isOnPhishingList(url.href), 'The specified URL is not allowed.'); + } + catch (error) { + throw new Error(`Invalid URL: ${error?.code === 'ERR_ASSERTION' ? error.message : 'Unable to parse URL.'}`); +diff --git a/dist/ui.mjs.map b/dist/ui.mjs.map +index 1600ced3d6bfc87a5b75328b776dc93e54402201..0d1ffdd50173f534e9dc2ce041ca83e7926750b0 100644 +--- a/dist/ui.mjs.map ++++ b/dist/ui.mjs.map +@@ -1 +1 @@ +-{"version":3,"file":"ui.mjs","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from '@metamask/snaps-sdk';\nimport { NodeType } from '@metamask/snaps-sdk';\nimport type {\n BoldChildren,\n GenericSnapElement,\n ItalicChildren,\n JSXElement,\n LinkElement,\n Nestable,\n RowChildren,\n SnapNode,\n StandardFormattingElement,\n TextChildren,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n Italic,\n Link,\n Bold,\n Row,\n Text,\n Field,\n Image,\n Input,\n Heading,\n Form,\n Divider,\n Spinner,\n Copyable,\n Box,\n Button,\n Address,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n assert,\n assertExhaustive,\n hasProperty,\n isPlainObject,\n} from '@metamask/utils';\nimport { lexer, walkTokens } from 'marked';\nimport type { Token, Tokens } from 'marked';\n\nconst MAX_TEXT_LENGTH = 50_000; // 50 kb\nconst ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n\n/**\n * Get the button variant from a legacy button component variant.\n *\n * @param variant - The legacy button component variant.\n * @returns The button variant.\n */\nfunction getButtonVariant(variant?: 'primary' | 'secondary' | undefined) {\n switch (variant) {\n case 'primary':\n return 'primary';\n case 'secondary':\n return 'destructive';\n default:\n return undefined;\n }\n}\n\n/**\n * Get the children of a JSX element. If there is only one child, the child is\n * returned directly. Otherwise, the children are returned as an array.\n *\n * @param elements - The JSX elements.\n * @returns The child or children.\n */\nfunction getChildren(elements: Type[]) {\n if (elements.length === 1) {\n return elements[0];\n }\n\n return elements;\n}\n\n/**\n * Get the text of a link token.\n *\n * @param token - The link token.\n * @returns The text of the link token.\n */\nfunction getLinkText(token: Tokens.Link | Tokens.Generic) {\n if (token.tokens && token.tokens.length > 0) {\n return getChildren(token.tokens.flatMap(getTextChildFromToken));\n }\n\n return token.href;\n}\n\n/**\n * Get the text child from a list of markdown tokens.\n *\n * @param tokens - The markdown tokens.\n * @returns The text child.\n */\nfunction getTextChildFromTokens(tokens: Token[]) {\n return getChildren(tokens.flatMap(getTextChildFromToken));\n}\n\n/**\n * Get the text child from a markdown token.\n *\n * @param token - The markdown token.\n * @returns The text child.\n */\nfunction getTextChildFromToken(token: Token): TextChildren {\n switch (token.type) {\n case 'link': {\n return ;\n }\n\n case 'text':\n return token.text;\n\n case 'strong':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as BoldChildren\n }\n \n );\n\n case 'em':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as ItalicChildren\n }\n \n );\n\n default:\n return null;\n }\n}\n\n/**\n * Get all text children from a markdown string.\n *\n * @param value - The markdown string.\n * @returns The text children.\n */\nexport function getTextChildren(\n value: string,\n): (string | StandardFormattingElement | LinkElement)[] {\n const rootTokens = lexer(value, { gfm: false });\n const children: (string | StandardFormattingElement | LinkElement | null)[] =\n [];\n\n walkTokens(rootTokens, (token) => {\n if (token.type === 'paragraph') {\n if (children.length > 0) {\n children.push('\\n\\n');\n }\n\n const { tokens } = token as Tokens.Paragraph;\n // We do not need to consider nesting deeper than 1 level here and we can therefore cast.\n children.push(\n ...(tokens.flatMap(getTextChildFromToken) as (\n | string\n | StandardFormattingElement\n | LinkElement\n | null\n )[]),\n );\n }\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n return children.filter((child) => child !== null) as (\n | string\n | StandardFormattingElement\n | LinkElement\n )[];\n}\n\n/**\n * Validate the text size of a component. The text size is the total length of\n * all text in the component.\n *\n * @param component - The component to validate.\n * @throws An error if the text size exceeds the maximum allowed size.\n */\nfunction validateComponentTextSize(component: Component) {\n const textSize = getTotalTextLength(component);\n assert(\n textSize <= MAX_TEXT_LENGTH,\n `The text in a Snap UI may not be larger than ${\n MAX_TEXT_LENGTH / 1000\n } kB.`,\n );\n}\n\n/**\n * Get a JSX element from a legacy UI component. This supports all legacy UI\n * components, and maps them to their JSX equivalents where possible.\n *\n * This function validates the text size of the component, but does not validate\n * the total size. The total size of the component should be validated before\n * calling this function.\n *\n * @param legacyComponent - The legacy UI component.\n * @returns The JSX element.\n */\nexport function getJsxElementFromComponent(\n legacyComponent: Component,\n): JSXElement {\n validateComponentTextSize(legacyComponent);\n\n /**\n * Get the JSX element for a component. This function is recursive and will\n * call itself for child components.\n *\n * @param component - The component to convert to a JSX element.\n * @returns The JSX element.\n */\n function getElement(component: Component) {\n switch (component.type) {\n case NodeType.Address:\n return
;\n\n case NodeType.Button:\n return (\n \n {component.value}\n \n );\n\n case NodeType.Copyable:\n return (\n \n );\n\n case NodeType.Divider:\n return ;\n\n case NodeType.Form:\n return (\n
\n {getChildren(component.children.map(getElement))}\n
\n );\n\n case NodeType.Heading:\n return ;\n\n case NodeType.Image:\n // `Image` supports `alt`, but the legacy `Image` component does not.\n return ;\n\n case NodeType.Input:\n return (\n \n \n \n );\n\n case NodeType.Panel:\n // `Panel` is renamed to `Box` in JSX.\n return (\n \n );\n\n case NodeType.Row:\n return (\n \n {getElement(component.value) as RowChildren}\n \n );\n\n case NodeType.Spinner:\n return ;\n\n case NodeType.Text:\n return {getChildren(getTextChildren(component.value))};\n\n /* istanbul ignore next 2 */\n default:\n return assertExhaustive(component);\n }\n }\n\n return getElement(legacyComponent);\n}\n\n/**\n * Extract all links from a Markdown text string using the `marked` lexer.\n *\n * @param text - The markdown text string.\n * @returns A list of URLs linked to in the string.\n */\nfunction getMarkdownLinks(text: string) {\n const tokens = lexer(text, { gfm: false });\n const links: Tokens.Link[] = [];\n\n // Walk the lexed tokens and collect all link tokens\n walkTokens(tokens, (token) => {\n if (token.type === 'link') {\n links.push(token as Tokens.Link);\n }\n });\n\n return links;\n}\n\n/**\n * Validate a link against the phishing list.\n *\n * @param link - The link to validate.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n */\nexport function validateLink(\n link: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n try {\n const url = new URL(link);\n assert(\n ALLOWED_PROTOCOLS.includes(url.protocol),\n `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,\n );\n\n const hostname =\n url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname;\n\n assert(!isOnPhishingList(hostname), 'The specified URL is not allowed.');\n } catch (error) {\n throw new Error(\n `Invalid URL: ${\n error?.code === 'ERR_ASSERTION' ? error.message : 'Unable to parse URL.'\n }`,\n );\n }\n}\n\n/**\n * Search for Markdown links in a string and checks them against the phishing\n * list.\n *\n * @param text - The text to verify.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the text contains a link that is not allowed.\n */\nexport function validateTextLinks(\n text: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n const links = getMarkdownLinks(text);\n\n for (const link of links) {\n validateLink(link.href, isOnPhishingList);\n }\n}\n\n/**\n * Walk a JSX tree and validate each {@link LinkElement} node against the\n * phishing list.\n *\n * @param node - The JSX node to walk.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n */\nexport function validateJsxLinks(\n node: JSXElement,\n isOnPhishingList: (url: string) => boolean,\n) {\n walkJsx(node, (childNode) => {\n if (childNode.type !== 'Link') {\n return;\n }\n\n validateLink(childNode.props.href, isOnPhishingList);\n });\n}\n\n/**\n * Calculate the total length of all text in the component.\n *\n * @param component - A custom UI component.\n * @returns The total length of all text components in the component.\n */\nexport function getTotalTextLength(component: Component): number {\n const { type } = component;\n\n switch (type) {\n case NodeType.Panel:\n return component.children.reduce(\n // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n (sum, node) => sum + getTotalTextLength(node),\n 0,\n );\n\n case NodeType.Row:\n return getTotalTextLength(component.value);\n\n case NodeType.Text:\n return component.value.length;\n\n default:\n return 0;\n }\n}\n\n/**\n * Check if a JSX element has children.\n *\n * @param element - A JSX element.\n * @returns `true` if the element has children, `false` otherwise.\n */\nexport function hasChildren(\n element: Element,\n): element is Element & {\n props: { children: Nestable };\n} {\n return hasProperty(element.props, 'children');\n}\n\n/**\n * Filter a JSX child to remove `null`, `undefined`, plain booleans, and empty\n * strings.\n *\n * @param child - The JSX child to filter.\n * @returns `true` if the child is not `null`, `undefined`, a plain boolean, or\n * an empty string, `false` otherwise.\n */\nfunction filterJsxChild(child: JSXElement | string | boolean | null): boolean {\n return Boolean(child) && child !== true;\n}\n\n/**\n * Get the children of a JSX element as an array. If the element has only one\n * child, the child is returned as an array.\n *\n * @param element - A JSX element.\n * @returns The children of the element.\n */\nexport function getJsxChildren(element: JSXElement): (JSXElement | string)[] {\n if (hasChildren(element)) {\n if (Array.isArray(element.props.children)) {\n // @ts-expect-error - Each member of the union type has signatures, but\n // none of those signatures are compatible with each other.\n return element.props.children.filter(filterJsxChild).flat(Infinity);\n }\n\n if (element.props.children) {\n return [element.props.children];\n }\n }\n\n return [];\n}\n\n/**\n * Walk a JSX tree and call a callback on each node.\n *\n * @param node - The JSX node to walk.\n * @param callback - The callback to call on each node.\n * @param depth - The current depth in the JSX tree for a walk.\n * @returns The result of the callback, if any.\n */\nexport function walkJsx(\n node: JSXElement | JSXElement[],\n callback: (node: JSXElement, depth: number) => Value | undefined,\n depth = 0,\n): Value | undefined {\n if (Array.isArray(node)) {\n for (const child of node) {\n const childResult = walkJsx(child as JSXElement, callback, depth);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n\n return undefined;\n }\n\n const result = callback(node, depth);\n if (result !== undefined) {\n return result;\n }\n\n if (\n hasProperty(node, 'props') &&\n isPlainObject(node.props) &&\n hasProperty(node.props, 'children')\n ) {\n const children = getJsxChildren(node);\n for (const child of children) {\n if (isPlainObject(child)) {\n const childResult = walkJsx(child, callback, depth + 1);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Serialise a JSX prop to a string.\n *\n * @param prop - The JSX prop.\n * @returns The serialised JSX prop.\n */\nfunction serialiseProp(prop: unknown): string {\n if (typeof prop === 'string') {\n return `\"${prop}\"`;\n }\n\n return `{${JSON.stringify(prop)}}`;\n}\n\n/**\n * Serialise JSX props to a string.\n *\n * @param props - The JSX props.\n * @returns The serialised JSX props.\n */\nfunction serialiseProps(props: Record): string {\n return Object.entries(props)\n .filter(([key]) => key !== 'children')\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => ` ${key}=${serialiseProp(value)}`)\n .join('');\n}\n\n/**\n * Serialise a JSX node to a string.\n *\n * @param node - The JSX node.\n * @param indentation - The indentation level. Defaults to `0`. This should not\n * be set by the caller, as it is used for recursion.\n * @returns The serialised JSX node.\n */\nexport function serialiseJsx(node: SnapNode, indentation = 0): string {\n if (Array.isArray(node)) {\n return node.map((child) => serialiseJsx(child, indentation)).join('');\n }\n\n const indent = ' '.repeat(indentation);\n if (typeof node === 'string') {\n return `${indent}${node}\\n`;\n }\n\n if (!node) {\n return '';\n }\n\n const { type, props } = node as GenericSnapElement;\n const trailingNewline = indentation > 0 ? '\\n' : '';\n\n if (hasProperty(props, 'children')) {\n const children = serialiseJsx(props.children as SnapNode, indentation + 1);\n return `${indent}<${type}${serialiseProps(\n props,\n )}>\\n${children}${indent}${trailingNewline}`;\n }\n\n return `${indent}<${type}${serialiseProps(props)} />${trailingNewline}`;\n}\n"]} +\ No newline at end of file ++{"version":3,"file":"ui.mjs","sourceRoot":"","sources":["../src/ui.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from '@metamask/snaps-sdk';\nimport { NodeType } from '@metamask/snaps-sdk';\nimport type {\n BoldChildren,\n GenericSnapElement,\n ItalicChildren,\n JSXElement,\n LinkElement,\n Nestable,\n RowChildren,\n SnapNode,\n StandardFormattingElement,\n TextChildren,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n Italic,\n Link,\n Bold,\n Row,\n Text,\n Field,\n Image,\n Input,\n Heading,\n Form,\n Divider,\n Spinner,\n Copyable,\n Box,\n Button,\n Address,\n} from '@metamask/snaps-sdk/jsx';\nimport {\n assert,\n assertExhaustive,\n hasProperty,\n isPlainObject,\n} from '@metamask/utils';\nimport { lexer, walkTokens } from 'marked';\nimport type { Token, Tokens } from 'marked';\n\nconst MAX_TEXT_LENGTH = 50_000; // 50 kb\nconst ALLOWED_PROTOCOLS = ['https:', 'mailto:'];\n\n/**\n * Get the button variant from a legacy button component variant.\n *\n * @param variant - The legacy button component variant.\n * @returns The button variant.\n */\nfunction getButtonVariant(variant?: 'primary' | 'secondary' | undefined) {\n switch (variant) {\n case 'primary':\n return 'primary';\n case 'secondary':\n return 'destructive';\n default:\n return undefined;\n }\n}\n\n/**\n * Get the children of a JSX element. If there is only one child, the child is\n * returned directly. Otherwise, the children are returned as an array.\n *\n * @param elements - The JSX elements.\n * @returns The child or children.\n */\nfunction getChildren(elements: Type[]) {\n if (elements.length === 1) {\n return elements[0];\n }\n\n return elements;\n}\n\n/**\n * Get the text of a link token.\n *\n * @param token - The link token.\n * @returns The text of the link token.\n */\nfunction getLinkText(token: Tokens.Link | Tokens.Generic) {\n if (token.tokens && token.tokens.length > 0) {\n return getChildren(token.tokens.flatMap(getTextChildFromToken));\n }\n\n return token.href;\n}\n\n/**\n * Get the text child from a list of markdown tokens.\n *\n * @param tokens - The markdown tokens.\n * @returns The text child.\n */\nfunction getTextChildFromTokens(tokens: Token[]) {\n return getChildren(tokens.flatMap(getTextChildFromToken));\n}\n\n/**\n * Get the text child from a markdown token.\n *\n * @param token - The markdown token.\n * @returns The text child.\n */\nfunction getTextChildFromToken(token: Token): TextChildren {\n switch (token.type) {\n case 'link': {\n return ;\n }\n\n case 'text':\n return token.text;\n\n case 'strong':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as BoldChildren\n }\n \n );\n\n case 'em':\n return (\n \n {\n getTextChildFromTokens(\n // Due to the way `marked` is typed, `token.tokens` can be\n // `undefined`, but it's a required field of `Tokens.Bold`, so we\n // can safely cast it to `Token[]`.\n token.tokens as Token[],\n ) as ItalicChildren\n }\n \n );\n\n default:\n return null;\n }\n}\n\n/**\n * Get all text children from a markdown string.\n *\n * @param value - The markdown string.\n * @returns The text children.\n */\nexport function getTextChildren(\n value: string,\n): (string | StandardFormattingElement | LinkElement)[] {\n const rootTokens = lexer(value, { gfm: false });\n const children: (string | StandardFormattingElement | LinkElement | null)[] =\n [];\n\n walkTokens(rootTokens, (token) => {\n if (token.type === 'paragraph') {\n if (children.length > 0) {\n children.push('\\n\\n');\n }\n\n const { tokens } = token as Tokens.Paragraph;\n // We do not need to consider nesting deeper than 1 level here and we can therefore cast.\n children.push(\n ...(tokens.flatMap(getTextChildFromToken) as (\n | string\n | StandardFormattingElement\n | LinkElement\n | null\n )[]),\n );\n }\n });\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n return children.filter((child) => child !== null) as (\n | string\n | StandardFormattingElement\n | LinkElement\n )[];\n}\n\n/**\n * Validate the text size of a component. The text size is the total length of\n * all text in the component.\n *\n * @param component - The component to validate.\n * @throws An error if the text size exceeds the maximum allowed size.\n */\nfunction validateComponentTextSize(component: Component) {\n const textSize = getTotalTextLength(component);\n assert(\n textSize <= MAX_TEXT_LENGTH,\n `The text in a Snap UI may not be larger than ${\n MAX_TEXT_LENGTH / 1000\n } kB.`,\n );\n}\n\n/**\n * Get a JSX element from a legacy UI component. This supports all legacy UI\n * components, and maps them to their JSX equivalents where possible.\n *\n * This function validates the text size of the component, but does not validate\n * the total size. The total size of the component should be validated before\n * calling this function.\n *\n * @param legacyComponent - The legacy UI component.\n * @returns The JSX element.\n */\nexport function getJsxElementFromComponent(\n legacyComponent: Component,\n): JSXElement {\n validateComponentTextSize(legacyComponent);\n\n /**\n * Get the JSX element for a component. This function is recursive and will\n * call itself for child components.\n *\n * @param component - The component to convert to a JSX element.\n * @returns The JSX element.\n */\n function getElement(component: Component) {\n switch (component.type) {\n case NodeType.Address:\n return
;\n\n case NodeType.Button:\n return (\n \n {component.value}\n \n );\n\n case NodeType.Copyable:\n return (\n \n );\n\n case NodeType.Divider:\n return ;\n\n case NodeType.Form:\n return (\n
\n {getChildren(component.children.map(getElement))}\n
\n );\n\n case NodeType.Heading:\n return ;\n\n case NodeType.Image:\n // `Image` supports `alt`, but the legacy `Image` component does not.\n return ;\n\n case NodeType.Input:\n return (\n \n \n \n );\n\n case NodeType.Panel:\n // `Panel` is renamed to `Box` in JSX.\n return (\n \n );\n\n case NodeType.Row:\n return (\n \n {getElement(component.value) as RowChildren}\n \n );\n\n case NodeType.Spinner:\n return ;\n\n case NodeType.Text:\n return {getChildren(getTextChildren(component.value))};\n\n /* istanbul ignore next 2 */\n default:\n return assertExhaustive(component);\n }\n }\n\n return getElement(legacyComponent);\n}\n\n/**\n * Extract all links from a Markdown text string using the `marked` lexer.\n *\n * @param text - The markdown text string.\n * @returns A list of URLs linked to in the string.\n */\nfunction getMarkdownLinks(text: string) {\n const tokens = lexer(text, { gfm: false });\n const links: Tokens.Link[] = [];\n\n // Walk the lexed tokens and collect all link tokens\n walkTokens(tokens, (token) => {\n if (token.type === 'link') {\n links.push(token as Tokens.Link);\n }\n });\n\n return links;\n}\n\n/**\n * Validate a link against the phishing list.\n *\n * @param link - The link to validate.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the link is invalid.\n */\nexport function validateLink(\n link: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n try {\n const url = new URL(link);\n assert(\n ALLOWED_PROTOCOLS.includes(url.protocol),\n `Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,\n );\n\n if (url.protocol === 'mailto:') {\n const emails = url.pathname.split(',');\n for (const email of emails) {\n const hostname = email.split('@')[1];\n assert(!hostname.includes(':'));\n const href = `https://${hostname}`;\n assert(!isOnPhishingList(href), 'The specified URL is not allowed.');\n }\n\n return;\n }\n\n assert(!isOnPhishingList(url.href), 'The specified URL is not allowed.');\n } catch (error) {\n throw new Error(\n `Invalid URL: ${\n error?.code === 'ERR_ASSERTION' ? error.message : 'Unable to parse URL.'\n }`,\n );\n }\n}\n\n/**\n * Search for Markdown links in a string and checks them against the phishing\n * list.\n *\n * @param text - The text to verify.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n * @throws If the text contains a link that is not allowed.\n */\nexport function validateTextLinks(\n text: string,\n isOnPhishingList: (url: string) => boolean,\n) {\n const links = getMarkdownLinks(text);\n\n for (const link of links) {\n validateLink(link.href, isOnPhishingList);\n }\n}\n\n/**\n * Walk a JSX tree and validate each {@link LinkElement} node against the\n * phishing list.\n *\n * @param node - The JSX node to walk.\n * @param isOnPhishingList - The function that checks the link against the\n * phishing list.\n */\nexport function validateJsxLinks(\n node: JSXElement,\n isOnPhishingList: (url: string) => boolean,\n) {\n walkJsx(node, (childNode) => {\n if (childNode.type !== 'Link') {\n return;\n }\n\n validateLink(childNode.props.href, isOnPhishingList);\n });\n}\n\n/**\n * Calculate the total length of all text in the component.\n *\n * @param component - A custom UI component.\n * @returns The total length of all text components in the component.\n */\nexport function getTotalTextLength(component: Component): number {\n const { type } = component;\n\n switch (type) {\n case NodeType.Panel:\n return component.children.reduce(\n // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n (sum, node) => sum + getTotalTextLength(node),\n 0,\n );\n\n case NodeType.Row:\n return getTotalTextLength(component.value);\n\n case NodeType.Text:\n return component.value.length;\n\n default:\n return 0;\n }\n}\n\n/**\n * Check if a JSX element has children.\n *\n * @param element - A JSX element.\n * @returns `true` if the element has children, `false` otherwise.\n */\nexport function hasChildren(\n element: Element,\n): element is Element & {\n props: { children: Nestable };\n} {\n return hasProperty(element.props, 'children');\n}\n\n/**\n * Filter a JSX child to remove `null`, `undefined`, plain booleans, and empty\n * strings.\n *\n * @param child - The JSX child to filter.\n * @returns `true` if the child is not `null`, `undefined`, a plain boolean, or\n * an empty string, `false` otherwise.\n */\nfunction filterJsxChild(child: JSXElement | string | boolean | null): boolean {\n return Boolean(child) && child !== true;\n}\n\n/**\n * Get the children of a JSX element as an array. If the element has only one\n * child, the child is returned as an array.\n *\n * @param element - A JSX element.\n * @returns The children of the element.\n */\nexport function getJsxChildren(element: JSXElement): (JSXElement | string)[] {\n if (hasChildren(element)) {\n if (Array.isArray(element.props.children)) {\n // @ts-expect-error - Each member of the union type has signatures, but\n // none of those signatures are compatible with each other.\n return element.props.children.filter(filterJsxChild).flat(Infinity);\n }\n\n if (element.props.children) {\n return [element.props.children];\n }\n }\n\n return [];\n}\n\n/**\n * Walk a JSX tree and call a callback on each node.\n *\n * @param node - The JSX node to walk.\n * @param callback - The callback to call on each node.\n * @param depth - The current depth in the JSX tree for a walk.\n * @returns The result of the callback, if any.\n */\nexport function walkJsx(\n node: JSXElement | JSXElement[],\n callback: (node: JSXElement, depth: number) => Value | undefined,\n depth = 0,\n): Value | undefined {\n if (Array.isArray(node)) {\n for (const child of node) {\n const childResult = walkJsx(child as JSXElement, callback, depth);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n\n return undefined;\n }\n\n const result = callback(node, depth);\n if (result !== undefined) {\n return result;\n }\n\n if (\n hasProperty(node, 'props') &&\n isPlainObject(node.props) &&\n hasProperty(node.props, 'children')\n ) {\n const children = getJsxChildren(node);\n for (const child of children) {\n if (isPlainObject(child)) {\n const childResult = walkJsx(child, callback, depth + 1);\n if (childResult !== undefined) {\n return childResult;\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Serialise a JSX prop to a string.\n *\n * @param prop - The JSX prop.\n * @returns The serialised JSX prop.\n */\nfunction serialiseProp(prop: unknown): string {\n if (typeof prop === 'string') {\n return `\"${prop}\"`;\n }\n\n return `{${JSON.stringify(prop)}}`;\n}\n\n/**\n * Serialise JSX props to a string.\n *\n * @param props - The JSX props.\n * @returns The serialised JSX props.\n */\nfunction serialiseProps(props: Record): string {\n return Object.entries(props)\n .filter(([key]) => key !== 'children')\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => ` ${key}=${serialiseProp(value)}`)\n .join('');\n}\n\n/**\n * Serialise a JSX node to a string.\n *\n * @param node - The JSX node.\n * @param indentation - The indentation level. Defaults to `0`. This should not\n * be set by the caller, as it is used for recursion.\n * @returns The serialised JSX node.\n */\nexport function serialiseJsx(node: SnapNode, indentation = 0): string {\n if (Array.isArray(node)) {\n return node.map((child) => serialiseJsx(child, indentation)).join('');\n }\n\n const indent = ' '.repeat(indentation);\n if (typeof node === 'string') {\n return `${indent}${node}\\n`;\n }\n\n if (!node) {\n return '';\n }\n\n const { type, props } = node as GenericSnapElement;\n const trailingNewline = indentation > 0 ? '\\n' : '';\n\n if (hasProperty(props, 'children')) {\n const children = serialiseJsx(props.children as SnapNode, indentation + 1);\n return `${indent}<${type}${serialiseProps(\n props,\n )}>\\n${children}${indent}${trailingNewline}`;\n }\n\n return `${indent}<${type}${serialiseProps(props)} />${trailingNewline}`;\n}\n"]} +\ No newline at end of file diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 128a415246cf..ca5e3abf4985 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -2761,7 +2761,7 @@ export default class MetamaskController extends EventEmitter { 'PhishingController:maybeUpdateState', ); }, - isOnPhishingList: (sender) => { + isOnPhishingList: (url) => { const { usePhishDetect } = this.preferencesController.store.getState(); @@ -2771,7 +2771,7 @@ export default class MetamaskController extends EventEmitter { return this.controllerMessenger.call( 'PhishingController:testOrigin', - sender.url, + url, ).result; }, createInterface: this.controllerMessenger.call.bind( diff --git a/package.json b/package.json index bde7fa9853b8..82592d8b0d45 100644 --- a/package.json +++ b/package.json @@ -266,7 +266,8 @@ "@metamask/network-controller@npm:^17.0.0": "patch:@metamask/network-controller@npm%3A21.0.0#~/.yarn/patches/@metamask-network-controller-npm-21.0.0-559aa8e395.patch", "@metamask/network-controller@npm:^19.0.0": "patch:@metamask/network-controller@npm%3A21.0.0#~/.yarn/patches/@metamask-network-controller-npm-21.0.0-559aa8e395.patch", "@metamask/network-controller@npm:^20.0.0": "patch:@metamask/network-controller@npm%3A21.0.0#~/.yarn/patches/@metamask-network-controller-npm-21.0.0-559aa8e395.patch", - "path-to-regexp": "1.9.0" + "path-to-regexp": "1.9.0", + "@metamask/snaps-utils@npm:^8.1.1": "patch:@metamask/snaps-utils@npm%3A8.1.1#~/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch" }, "dependencies": { "@babel/runtime": "patch:@babel/runtime@npm%3A7.24.0#~/.yarn/patches/@babel-runtime-npm-7.24.0-7eb1dd11a2.patch", @@ -358,7 +359,7 @@ "@metamask/snaps-execution-environments": "^6.7.2", "@metamask/snaps-rpc-methods": "^11.1.1", "@metamask/snaps-sdk": "^6.5.1", - "@metamask/snaps-utils": "^8.1.1", + "@metamask/snaps-utils": "patch:@metamask/snaps-utils@npm%3A8.1.1#~/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch", "@metamask/transaction-controller": "^37.0.0", "@metamask/user-operation-controller": "^13.0.0", "@metamask/utils": "^9.1.0", diff --git a/yarn.lock b/yarn.lock index 08b76a2b2048..36c6e53aed30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6364,6 +6364,37 @@ __metadata: languageName: node linkType: hard +"@metamask/snaps-utils@npm:8.1.1": + version: 8.1.1 + resolution: "@metamask/snaps-utils@npm:8.1.1" + dependencies: + "@babel/core": "npm:^7.23.2" + "@babel/types": "npm:^7.23.0" + "@metamask/base-controller": "npm:^6.0.2" + "@metamask/key-tree": "npm:^9.1.2" + "@metamask/permission-controller": "npm:^11.0.0" + "@metamask/rpc-errors": "npm:^6.3.1" + "@metamask/slip44": "npm:^4.0.0" + "@metamask/snaps-registry": "npm:^3.2.1" + "@metamask/snaps-sdk": "npm:^6.5.0" + "@metamask/superstruct": "npm:^3.1.0" + "@metamask/utils": "npm:^9.2.1" + "@noble/hashes": "npm:^1.3.1" + "@scure/base": "npm:^1.1.1" + chalk: "npm:^4.1.2" + cron-parser: "npm:^4.5.0" + fast-deep-equal: "npm:^3.1.3" + fast-json-stable-stringify: "npm:^2.1.0" + fast-xml-parser: "npm:^4.4.1" + marked: "npm:^12.0.1" + rfdc: "npm:^1.3.0" + semver: "npm:^7.5.4" + ses: "npm:^1.1.0" + validate-npm-package-name: "npm:^5.0.0" + checksum: 10/f4ceb52a1f9578993c88c82a67f4f041309af51c83ff5caa3fed080f36b54d14ea7da807ce1cf19a13600dd0e77c51af70398e8c7bb78f0ba99a037f4d22610f + languageName: node + linkType: hard + "@metamask/snaps-utils@npm:^7.4.0, @metamask/snaps-utils@npm:^7.8.0": version: 7.8.1 resolution: "@metamask/snaps-utils@npm:7.8.1" @@ -6395,9 +6426,9 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-utils@npm:^8.1.1": +"@metamask/snaps-utils@patch:@metamask/snaps-utils@npm%3A8.1.1#~/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch": version: 8.1.1 - resolution: "@metamask/snaps-utils@npm:8.1.1" + resolution: "@metamask/snaps-utils@patch:@metamask/snaps-utils@npm%3A8.1.1#~/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch::version=8.1.1&hash=d09097" dependencies: "@babel/core": "npm:^7.23.2" "@babel/types": "npm:^7.23.0" @@ -6422,7 +6453,7 @@ __metadata: semver: "npm:^7.5.4" ses: "npm:^1.1.0" validate-npm-package-name: "npm:^5.0.0" - checksum: 10/f4ceb52a1f9578993c88c82a67f4f041309af51c83ff5caa3fed080f36b54d14ea7da807ce1cf19a13600dd0e77c51af70398e8c7bb78f0ba99a037f4d22610f + checksum: 10/6b1d3d70c5ebee684d5b76bf911c66ebd122a0607cefcfc9fffd4bf6882a7acfca655d97be87c0f7f47e59a981b58234578ed8a123e554a36e6c48ff87492655 languageName: node linkType: hard @@ -26145,7 +26176,7 @@ __metadata: "@metamask/snaps-execution-environments": "npm:^6.7.2" "@metamask/snaps-rpc-methods": "npm:^11.1.1" "@metamask/snaps-sdk": "npm:^6.5.1" - "@metamask/snaps-utils": "npm:^8.1.1" + "@metamask/snaps-utils": "patch:@metamask/snaps-utils@npm%3A8.1.1#~/.yarn/patches/@metamask-snaps-utils-npm-8.1.1-7d5dd6a26a.patch" "@metamask/test-bundler": "npm:^1.0.0" "@metamask/test-dapp": "npm:^8.4.0" "@metamask/transaction-controller": "npm:^37.0.0" From 5b4c287d1ff43317bb71038a0b25853b8e5c7edc Mon Sep 17 00:00:00 2001 From: David Drazic Date: Tue, 15 Oct 2024 16:37:50 +0200 Subject: [PATCH 12/46] =?UTF-8?q?fix:=20[cherry-pick][V12.5.0]=20sticky=20?= =?UTF-8?q?footer=20UI=20issue=20on=20Snaps=20Home=20Page=E2=80=A6=20(#278?= =?UTF-8?q?30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-picked from: https://github.com/MetaMask/metamask-extension/pull/27799 ## **Description** Fix issue with sticky Snaps UI Footer component in extended view. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27799?quickstart=1) ## **Related issues** Fixes: n/a ## **Manual testing steps** 1. Try all the Snaps that use custom footer (Home Page Snap, Custom Dialog Snap with custom UI, etc.). 2. Make sure that footer has correct width matching the width of the content view. ## **Screenshots/Recordings** ### **Before** ![image](https://github.com/user-attachments/assets/f2a2c924-2bd9-451e-9b26-aadda9e94b22) ### **After** ![Screenshot 2024-10-11 at 20 38 13](https://github.com/user-attachments/assets/644d97f6-89b3-4971-bc8e-d51322888788) ![Screenshot 2024-10-11 at 20 38 48](https://github.com/user-attachments/assets/b65b113c-8aa1-4d54-b70c-ab88dad41505) ![Screenshot 2024-10-11 at 20 40 55](https://github.com/user-attachments/assets/215ae7a8-4e20-4a6b-a2ff-f4276515ded4) ![Screenshot 2024-10-11 at 20 41 15](https://github.com/user-attachments/assets/fa3f324d-3fc3-473b-81ea-bc4ce65ebaf3) ![Screenshot 2024-10-11 at 20 56 29](https://github.com/user-attachments/assets/6ad44d4b-a869-4f2a-9043-397e5730e757) ## **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/develop/.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/develop/.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. --- .../app/snaps/snap-ui-renderer/index.scss | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ui/components/app/snaps/snap-ui-renderer/index.scss b/ui/components/app/snaps/snap-ui-renderer/index.scss index b1bc569af333..7e18e72c917f 100644 --- a/ui/components/app/snaps/snap-ui-renderer/index.scss +++ b/ui/components/app/snaps/snap-ui-renderer/index.scss @@ -1,4 +1,10 @@ +@use "design-system"; + .snap-ui-renderer { + $width-screen-sm-min: 85vw; + $width-screen-md-min: 80vw; + $width-screen-lg-min: 62vw; + &__content { margin-bottom: 0 !important; } @@ -69,5 +75,17 @@ &__footer { margin-top: auto; + + @include design-system.screen-sm-min { + max-width: $width-screen-sm-min; + } + + @include design-system.screen-md-min { + max-width: $width-screen-md-min; + } + + @include design-system.screen-lg-min { + max-width: $width-screen-lg-min; + } } } From c3a8cf87e0e129bd4336185062ee0d9fa6808db9 Mon Sep 17 00:00:00 2001 From: HJetpoluru Date: Tue, 15 Oct 2024 10:48:16 -0400 Subject: [PATCH 13/46] Fixed the changelog error --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0944136e1fe..2d163fb4790a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [12.5.0] -## [12.4.0] ## [12.4.1] ### Fixed - Fix crash on swaps review page ([#27708](https://github.com/MetaMask/metamask-extension/pull/27708)) @@ -5148,8 +5147,7 @@ Update styles and spacing on the critical error page ([#20350](https://github.c [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.5.0...HEAD -[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.4.0...v12.5.0 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.4.1...HEAD +[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.4.1...v12.5.0 [12.4.1]: https://github.com/MetaMask/metamask-extension/compare/v12.4.0...v12.4.1 [12.4.0]: https://github.com/MetaMask/metamask-extension/compare/v12.3.1...v12.4.0 [12.3.1]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...v12.3.1 From aa7634f069e9a9636208e17d8174f5b5c6547450 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 16 Oct 2024 00:26:51 +0530 Subject: [PATCH 14/46] cherry-pick: issue with nonce not updating correctly where there are multiple parallel transactions (#27852) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Fix issue with nonce not updating when there are multiple transaction created in parallel and once transaction is submitted. ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/27617 ## **Manual testing steps** 1. Go to testdapp 2. create 2 transactions and submit first one 3. Nonce for second transaction should update ## **Screenshots/Recordings** TODO ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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 - [ ] 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-extension/blob/develop/.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. --- .../confirm-transaction-base.component.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js index 31149997a39c..fc0b5933c2ff 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.component.js @@ -216,6 +216,8 @@ export default class ConfirmTransactionBase extends Component { useMaxValue, hasPriorityApprovalRequest, mostRecentOverviewPage, + txData, + getNextNonce, } = this.props; const { @@ -226,6 +228,7 @@ export default class ConfirmTransactionBase extends Component { isEthGasPriceFetched: prevIsEthGasPriceFetched, hexMaximumTransactionFee: prevHexMaximumTransactionFee, hasPriorityApprovalRequest: prevHasPriorityApprovalRequest, + txData: prevTxData, } = prevProps; const statusUpdated = transactionStatus !== prevTxStatus; @@ -233,6 +236,10 @@ export default class ConfirmTransactionBase extends Component { transactionStatus === TransactionStatus.dropped || transactionStatus === TransactionStatus.confirmed; + if (txData.id !== prevTxData.id) { + getNextNonce(); + } + if ( nextNonce !== prevNextNonce || customNonceValue !== prevCustomNonceValue From 516af0477c72b2aecffc52c6fcd76fe2659cb3f8 Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Tue, 15 Oct 2024 20:15:28 +0000 Subject: [PATCH 15/46] Version v12.4.2 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7b07834e387..9a2274c06810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [12.4.2] + ## [12.4.1] ### Fixed - Fix crash on swaps review page ([#27708](https://github.com/MetaMask/metamask-extension/pull/27708)) @@ -5144,7 +5146,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.4.1...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.4.2...HEAD +[12.4.2]: https://github.com/MetaMask/metamask-extension/compare/v12.4.1...v12.4.2 [12.4.1]: https://github.com/MetaMask/metamask-extension/compare/v12.4.0...v12.4.1 [12.4.0]: https://github.com/MetaMask/metamask-extension/compare/v12.3.1...v12.4.0 [12.3.1]: https://github.com/MetaMask/metamask-extension/compare/v12.3.0...v12.3.1 diff --git a/package.json b/package.json index 19c9a6c0400d..ad50f0b114c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "12.4.1", + "version": "12.4.2", "private": true, "repository": { "type": "git", From 1a65ee7696cacd8eb750c30ab49648f9401c7450 Mon Sep 17 00:00:00 2001 From: martahj Date: Tue, 15 Oct 2024 17:36:06 -0500 Subject: [PATCH 16/46] Fix/linea bufix 12.5 (#27876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Cherry-pick of https://github.com/MetaMask/metamask-extension/pull/27810 into 12.5.0. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27876?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/27804 ## **Manual testing steps** 1. Start a swap on Linea with a token that you have not granted approval for 2. Observe that the swap does not fail ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/57cdc5e5-cea7-48ad-ba13-38820ecc9155 ### **After** https://github.com/user-attachments/assets/91bbfbf4-8392-41ea-bfe8-d54813758f5c ## **Pre-merge author checklist** - [X] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. --- ui/ducks/swaps/swaps.js | 16 ++++++++++++++ ui/pages/swaps/awaiting-swap/awaiting-swap.js | 21 +++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/ui/ducks/swaps/swaps.js b/ui/ducks/swaps/swaps.js index 8abb63aa4a14..b6a1fe0125c0 100644 --- a/ui/ducks/swaps/swaps.js +++ b/ui/ducks/swaps/swaps.js @@ -5,6 +5,7 @@ import log from 'loglevel'; import { captureMessage } from '@sentry/browser'; import { TransactionType } from '@metamask/transaction-controller'; +import { CHAIN_IDS } from '../../../shared/constants/network'; import { addToken, addTransactionAndWaitForPublish, @@ -1242,6 +1243,21 @@ export const signAndSendTransactions = ( }, }, ); + if ( + [ + CHAIN_IDS.LINEA_MAINNET, + CHAIN_IDS.LINEA_GOERLI, + CHAIN_IDS.LINEA_SEPOLIA, + ].includes(chainId) + ) { + log.debug( + 'Delaying submitting trade tx to make Linea confirmation more likely', + ); + const waitPromise = new Promise((resolve) => + setTimeout(resolve, 5000), + ); + await waitPromise; + } } catch (e) { await dispatch(setSwapsErrorKey(SWAP_FAILED_ERROR)); history.push(SWAPS_ERROR_ROUTE); diff --git a/ui/pages/swaps/awaiting-swap/awaiting-swap.js b/ui/pages/swaps/awaiting-swap/awaiting-swap.js index e7f47bc3f006..660f7ef4fcae 100644 --- a/ui/pages/swaps/awaiting-swap/awaiting-swap.js +++ b/ui/pages/swaps/awaiting-swap/awaiting-swap.js @@ -97,6 +97,9 @@ export default function AwaitingSwap({ const [trackedQuotesExpiredEvent, setTrackedQuotesExpiredEvent] = useState(false); + const destinationTokenSymbol = + usedQuote?.destinationTokenInfo?.symbol || swapMetaData?.token_to; + let feeinUnformattedFiat; if (usedQuote && swapsGasPrice) { @@ -107,7 +110,7 @@ export default function AwaitingSwap({ currentCurrency, conversionRate: usdConversionRate, tradeValue: usedQuote?.trade?.value, - sourceSymbol: swapMetaData?.token_from, + sourceSymbol: usedQuote?.sourceTokenInfo?.symbol, sourceAmount: usedQuote.sourceAmount, chainId, }); @@ -123,13 +126,14 @@ export default function AwaitingSwap({ const currentSmartTransactionsEnabled = useSelector( getCurrentSmartTransactionsEnabled, ); + const swapSlippage = swapMetaData?.slippage || usedQuote?.slippage; const sensitiveProperties = { - token_from: swapMetaData?.token_from, + token_from: swapMetaData?.token_from || usedQuote?.sourceTokenInfo?.symbol, token_from_amount: swapMetaData?.token_from_amount, - token_to: swapMetaData?.token_to, + token_to: destinationTokenSymbol, request_type: fetchParams?.balanceError ? 'Quote' : 'Order', - slippage: swapMetaData?.slippage, - custom_slippage: swapMetaData?.slippage === 2, + slippage: swapSlippage, + custom_slippage: swapSlippage === 2, gas_fees: feeinUnformattedFiat, is_hardware_wallet: hardwareWalletUsed, hardware_wallet_type: hardwareWalletType, @@ -137,7 +141,6 @@ export default function AwaitingSwap({ current_stx_enabled: currentSmartTransactionsEnabled, stx_user_opt_in: smartTransactionsOptInStatus, }; - const baseNetworkUrl = rpcPrefs.blockExplorerUrl ?? SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP[chainId] ?? @@ -234,7 +237,7 @@ export default function AwaitingSwap({ className="awaiting-swap__amount-and-symbol" data-testid="awaiting-swap-amount-and-symbol" > - {swapMetaData?.token_to} + {destinationTokenSymbol} , ]); content = blockExplorerUrl && ( @@ -252,7 +255,7 @@ export default function AwaitingSwap({ key="swapTokenAvailable-2" className="awaiting-swap__amount-and-symbol" > - {`${tokensReceived || ''} ${swapMetaData?.token_to}`} + {`${tokensReceived || ''} ${destinationTokenSymbol}`} , ]); content = blockExplorerUrl && ( @@ -317,7 +320,7 @@ export default function AwaitingSwap({ } else if (errorKey) { await dispatch(navigateBackToBuildQuote(history)); } else if ( - isSwapsDefaultTokenSymbol(swapMetaData?.token_to, chainId) || + isSwapsDefaultTokenSymbol(destinationTokenSymbol, chainId) || swapComplete ) { history.push(DEFAULT_ROUTE); From e4672a884c72e3c4405ef5e81112236d4862ccd0 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 16 Oct 2024 12:35:06 +0200 Subject: [PATCH 17/46] fix: Correct conditions for triggering name lookup during send (#27880) Take changes from https://github.com/MetaMask/metamask-extension/commit/5e08c068f42220ecb98a5c2d0ae739e6412f4d67 ## **Description** Hotfixes a problem preventing certain name resolution Snaps from being triggered due to faulty `IS_FLASK` conditions in `12.4.1`. These conditions were removed in https://github.com/MetaMask/metamask-extension/pull/26242. This PR picks these changes from the previously mentioned PR, without touching the ENS integration. The problem in question occurs when trying to trigger name resolution for a given input. `lookupDomainName` is never called on stable unless the input looks similar to an ENS name. This prevents resolution of inputs that don't use TLDs for instance. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27880?quickstart=1) ## **Manual testing steps** 1. Use a build of stable 2. Install https://snaps.metamask.io/snap/npm/social-names-snap/ 3. See that you can resolve a Farcaster name using that Snap, e.g. `fc:frederik` 4. Check that you can also type a valid ENS name 5. Check that you can also type a valid address --------- Co-authored-by: Hassan Malik --- app/_locales/am/messages.json | 3 -- app/_locales/ar/messages.json | 3 -- app/_locales/bg/messages.json | 3 -- app/_locales/bn/messages.json | 3 -- app/_locales/ca/messages.json | 3 -- app/_locales/da/messages.json | 3 -- app/_locales/de/messages.json | 6 --- app/_locales/el/messages.json | 6 --- app/_locales/en/messages.json | 5 +-- app/_locales/en_GB/messages.json | 5 +-- app/_locales/es/messages.json | 6 --- app/_locales/es_419/messages.json | 3 -- app/_locales/et/messages.json | 3 -- app/_locales/fa/messages.json | 3 -- app/_locales/fi/messages.json | 3 -- app/_locales/fil/messages.json | 3 -- app/_locales/fr/messages.json | 6 --- app/_locales/he/messages.json | 3 -- app/_locales/hi/messages.json | 6 --- app/_locales/hr/messages.json | 3 -- app/_locales/hu/messages.json | 3 -- app/_locales/id/messages.json | 6 --- app/_locales/it/messages.json | 3 -- app/_locales/ja/messages.json | 6 --- app/_locales/kn/messages.json | 3 -- app/_locales/ko/messages.json | 6 --- app/_locales/lt/messages.json | 3 -- app/_locales/lv/messages.json | 3 -- app/_locales/ms/messages.json | 3 -- app/_locales/no/messages.json | 3 -- app/_locales/ph/messages.json | 3 -- app/_locales/pl/messages.json | 3 -- app/_locales/pt/messages.json | 6 --- app/_locales/pt_BR/messages.json | 3 -- app/_locales/ro/messages.json | 3 -- app/_locales/ru/messages.json | 6 --- app/_locales/sk/messages.json | 3 -- app/_locales/sl/messages.json | 3 -- app/_locales/sr/messages.json | 3 -- app/_locales/sv/messages.json | 3 -- app/_locales/sw/messages.json | 3 -- app/_locales/tl/messages.json | 6 --- app/_locales/tr/messages.json | 6 --- app/_locales/uk/messages.json | 3 -- app/_locales/vi/messages.json | 6 --- app/_locales/zh_CN/messages.json | 6 --- app/_locales/zh_TW/messages.json | 3 -- shared/modules/hexstring-utils.test.js | 45 ++++++++++++++++++- shared/modules/hexstring-utils.ts | 10 +++++ test/e2e/tests/account/import-flow.spec.js | 2 +- .../account/metamask-responsive-ui.spec.js | 2 +- test/e2e/tests/network/network-error.spec.js | 2 +- .../petnames/petnames-transactions.spec.js | 2 +- .../tests/settings/change-language.spec.ts | 6 ++- .../tests/swap-send/swap-send-test-utils.ts | 2 +- .../tokens/custom-token-send-transfer.spec.js | 2 +- test/e2e/tests/tokens/nft/send-nft.spec.js | 6 +-- .../tokens/send-erc20-to-contract.spec.js | 2 +- .../tests/transaction/gas-estimates.spec.js | 12 ++--- test/e2e/tests/transaction/send-eth.spec.js | 8 ++-- .../transaction/send-hex-address.spec.js | 8 ++-- test/e2e/user-actions-benchmark.js | 2 +- .../send/__snapshots__/send.test.js.snap | 2 +- .../multichain/pages/send/send.test.js | 2 +- ui/ducks/send/send.js | 12 +++-- ui/ducks/send/send.test.js | 4 +- .../add-recipient/domain-input.component.js | 18 +++----- 67 files changed, 100 insertions(+), 236 deletions(-) diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index cb193bc11c36..d3e41a97143d 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -530,9 +530,6 @@ "readdToken": { "message": "በመለያ አማራጮችዎ ምናሌ ውስጥ ወደ “ተለዋጭ ስም አክል” በመግባት ለወደፊቱ ይህን ተለዋጭ ስም መልሰው ማከል ይችላሉ።" }, - "recipientAddressPlaceholder": { - "message": "ፍለጋ፣ ለሕዝብ ክፍት የሆነ አድራሻ (0x), ወይም ENS" - }, "reject": { "message": "አይቀበሉ" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index e262cebf3537..e06284ba9a97 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -542,9 +542,6 @@ "readdToken": { "message": "يمكنك إضافة هذه العملة الرمزية مرة أخرى في المستقبل من خلال الانتقال إلى \"إضافة عملة رمزية\" في قائمة خيارات الحسابات الخاصة بك." }, - "recipientAddressPlaceholder": { - "message": "البحث، العنوان العام (0x)، أو ENS" - }, "reject": { "message": "رفض" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index 2169f13ecf9d..6a55cb677fae 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -541,9 +541,6 @@ "readdToken": { "message": "Можете да добавите този жетон в бъдеще, като отидете на „Добавяне на жетон“ в менюто с опции на акаунти." }, - "recipientAddressPlaceholder": { - "message": "Търсене, публичен адрес (0x) или ENS" - }, "reject": { "message": "Отхвърляне" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index 29e06173be17..5936e87ba918 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -539,9 +539,6 @@ "readdToken": { "message": "আপনি আপনার অ্যাকাউন্টস বিকল্পের মেনুতে \"টোকেনগুলি যোগ করুন\" এ গিয়ে ভবিষ্যতে আবার এই টোকেনটি যোগ করতে পারবেন। " }, - "recipientAddressPlaceholder": { - "message": "অনুসন্ধান, সার্বজনীন ঠিকানা (0x), বা ENS" - }, "reject": { "message": "প্রত্যাখ্যান" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index 4393ea21f108..a129476f1251 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -526,9 +526,6 @@ "readdToken": { "message": "Pots tornar a afegir aquesta fitxa en el futur anant a \"Afegir fitxa\" al menu d'opcions dels teus comptes." }, - "recipientAddressPlaceholder": { - "message": "Cerca, adreça pública (0x), o ENS" - }, "reject": { "message": "Rebutja" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index f5d7c9c89c3e..b67cfed09236 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -526,9 +526,6 @@ "readdToken": { "message": "Du kan tilføje denne token i fremtiden, ved at gå til \"Tilføj token\" under dine valgmenuen for dine konti." }, - "recipientAddressPlaceholder": { - "message": "Søg, offentlig adresse (0x) eller ENS" - }, "reject": { "message": "Afvis" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 5e1b32229bd1..71e3b3c39483 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Empfangen" }, - "recipientAddressPlaceholder": { - "message": "Öffentliche Adresse (0x) oder ENS-Name eingeben" - }, - "recipientAddressPlaceholderFlask": { - "message": "Öffentliche Adresse (0x) oder Domainname eingeben" - }, "recommendedGasLabel": { "message": "Empfohlen" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index d8f080e7752c..5fe99f91fd2d 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Λήψη" }, - "recipientAddressPlaceholder": { - "message": "Εισάγετε τη δημόσια διεύθυνση (0x) ή το όνομα ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Εισαγάγετε τη δημόσια διεύθυνση (0x) ή το όνομα τομέα" - }, "recommendedGasLabel": { "message": "Προτεινόμενο" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 27424ebb89df..f27f8e30e15d 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -4242,10 +4242,7 @@ "receive": { "message": "Receive" }, - "recipientAddressPlaceholder": { - "message": "Enter public address (0x) or ENS name" - }, - "recipientAddressPlaceholderFlask": { + "recipientAddressPlaceholderNew": { "message": "Enter public address (0x) or domain name" }, "recommendedGasLabel": { diff --git a/app/_locales/en_GB/messages.json b/app/_locales/en_GB/messages.json index b7e15bc86b55..4cf930dcc0ac 100644 --- a/app/_locales/en_GB/messages.json +++ b/app/_locales/en_GB/messages.json @@ -4207,10 +4207,7 @@ "receive": { "message": "Receive" }, - "recipientAddressPlaceholder": { - "message": "Enter public address (0x) or ENS name" - }, - "recipientAddressPlaceholderFlask": { + "recipientAddressPlaceholderNew": { "message": "Enter public address (0x) or domain name" }, "recommendedGasLabel": { diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index a20b831091a0..376fa10cee14 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Recibir" }, - "recipientAddressPlaceholder": { - "message": "Ingrese la dirección pública (0x) o el nombre de ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Ingrese la dirección pública (0x) o el nombre de dominio" - }, "recommendedGasLabel": { "message": "Recomendado" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index c406955c36c9..48a240c887a7 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1562,9 +1562,6 @@ "receive": { "message": "Recibir" }, - "recipientAddressPlaceholder": { - "message": "Búsqueda, dirección pública (0x) o ENS" - }, "recommendedGasLabel": { "message": "Recomendado" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index dbfe1f88fb55..4e00b3cf5d6a 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -535,9 +535,6 @@ "readdToken": { "message": "Saate selle loa tulevikus tagasi lisada, kui lähete oma kontovalikute menüüs vahelehele „Lisa luba“." }, - "recipientAddressPlaceholder": { - "message": "Otsing, avalik aadress (0x) või ENS" - }, "reject": { "message": "Lükka tagasi" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index 9f1d89793c1b..76abefbdbdf6 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -545,9 +545,6 @@ "readdToken": { "message": "شما میتوانید این رمزیاب را دوباره برای آینده با رفتن به گزینه \"Add token\" در مینوی تنظیمات حساب ها، اضافه نمایید." }, - "recipientAddressPlaceholder": { - "message": "جستجو، آدرس عمومی (0x)، یا ENS" - }, "reject": { "message": "عدم پذیرش" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 4f193797912c..bbf6d47c8fdb 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -542,9 +542,6 @@ "readdToken": { "message": "Voit lisätä tämän tietueen myöhemmin takaisin siirtymällä tilisi vaihtoehtovalikon kohtaan ”Lisää tietue”." }, - "recipientAddressPlaceholder": { - "message": "Haku, julkinen osoite (0x) tai ENS" - }, "reject": { "message": "Hylkää" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index ab098442e52e..f30e446877d2 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -469,9 +469,6 @@ "readdToken": { "message": "Puwede mong idagdag ulit ang token na ito sa hinaharap sa pamamagitan ng pagpunta sa “Magdagdag ng token” sa menu ng mga opsyon ng iyong mga accounts." }, - "recipientAddressPlaceholder": { - "message": "Maghanap, pampublikong address (0x), o ENS" - }, "reject": { "message": "Tanggihan" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 28d08810ae82..0bf19b0dca15 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Recevoir" }, - "recipientAddressPlaceholder": { - "message": "Saisissez l’adresse publique (0x) ou le nom de domaine ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Saisissez l’adresse publique (0x) ou le nom de domaine" - }, "recommendedGasLabel": { "message": "Recommandé" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index e29f44c9f834..ff2347a4036b 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -542,9 +542,6 @@ "readdToken": { "message": "באפשרותך להוסיף טוקן זה בחזרה בעתיד על ידי מעבר אל \"הוסף טוקן\" בתפריט אפשרויות החשבונות שלך." }, - "recipientAddressPlaceholder": { - "message": "חיפוש, כתובת ציבורית (0x), או ENS" - }, "reject": { "message": "דחה" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 2371df612b77..b8cd181f1344 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "प्राप्त करें" }, - "recipientAddressPlaceholder": { - "message": "सार्वजनिक एड्रेस (0x) या ENS नाम डालें" - }, - "recipientAddressPlaceholderFlask": { - "message": "पब्लिक एड्रेस (0x) या डोमेन नाम एंटर करें" - }, "recommendedGasLabel": { "message": "अनुशंसित" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index d7e62da80ba4..1216db40c3de 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -538,9 +538,6 @@ "readdToken": { "message": "Ovaj token možete dodati kasnije odlaskom pod stavku „Dodaj token” u izborniku mogućnosti računa. " }, - "recipientAddressPlaceholder": { - "message": "Pretraži, javne adrese (0x) ili ENS" - }, "reject": { "message": "Odbaci" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 456b63710dd6..805589352021 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -538,9 +538,6 @@ "readdToken": { "message": "Ezt a tokent a jövőben is hozzáadhatja, ha a fiókbeállítások menü „Token hozzáadása” elemére lép." }, - "recipientAddressPlaceholder": { - "message": "Keresés, nyilvános cím (0x) vagy ENS" - }, "reject": { "message": "Elutasítás" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 0f8ceacc9ea7..7895c262eec1 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Terima" }, - "recipientAddressPlaceholder": { - "message": "Masukkan alamat publik (0x) atau nama ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Masukkan alamat publik (0x) atau nama domain" - }, "recommendedGasLabel": { "message": "Direkomendasikan" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 9f9085f4ed81..e8d06cd4f0e7 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1236,9 +1236,6 @@ "receive": { "message": "Ricevi" }, - "recipientAddressPlaceholder": { - "message": "Ricerca, indirizzo pubblico (0x) o ENS" - }, "reject": { "message": "Annulla" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 44226098f705..e41aa542a902 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "受取" }, - "recipientAddressPlaceholder": { - "message": "パブリックアドレス (0x) またはENS名を入力してください" - }, - "recipientAddressPlaceholderFlask": { - "message": "パブリックアドレス (0x) またはドメイン名を入力してください" - }, "recommendedGasLabel": { "message": "推奨" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index 0b0479e3dddf..b7b5b19512cc 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -545,9 +545,6 @@ "readdToken": { "message": "ನಿಮ್ಮ ಖಾತೆಗಳ ಆಯ್ಕೆಗಳ ಮೆನುವಿನಲ್ಲಿ \"ಟೋಕನ್ ಸೇರಿಸು\" ಗೆ ಹೋಗುವ ಮೂಲಕ ನೀವು ಈ ಟೋಕನ್ ಅನ್ನು ಭವಿಷ್ಯದಲ್ಲಿ ಮರಳಿ ಸೇರಿಸಬಹುದು." }, - "recipientAddressPlaceholder": { - "message": "ಸಾರ್ವಜನಿಕ ವಿಳಾಸ (0x) ಅಥವಾ ENS ಹುಡುಕಿ" - }, "reject": { "message": "ತಿರಸ್ಕರಿಸಿ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 7286eefb09d7..39a2e3cff82a 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "받기" }, - "recipientAddressPlaceholder": { - "message": "공개 주소(0x) 또는 ENS 제목 입력" - }, - "recipientAddressPlaceholderFlask": { - "message": "공개 주소(0x) 또는 도메인 이름 입력" - }, "recommendedGasLabel": { "message": "권장됨" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 0600ea96f32b..7ddd53a7e1a2 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -545,9 +545,6 @@ "readdToken": { "message": "Šį žetoną galite bet kada galite įtraukti ir vėl, tiesiog savo paskyros parinkčių meniu nueikite į „Įtraukti žetoną“." }, - "recipientAddressPlaceholder": { - "message": "Ieška, viešieji adresai (0x) arba ENS" - }, "reject": { "message": "Atmesti" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index c0dfc6d573b8..0e0a935b2f69 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -541,9 +541,6 @@ "readdToken": { "message": "Jūs varat šo marķieri iestatīt atpakaļ nākotnē, konta opciju izvēlnē atverot \"Pievienot marķieri\"." }, - "recipientAddressPlaceholder": { - "message": "Meklēšana, publiskā adrese (0x) vai ENS" - }, "reject": { "message": "Noraidīt" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index b8a0cb2ac507..e4c60a72d7b9 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -525,9 +525,6 @@ "readdToken": { "message": "Anda boleh tambah token ini kembali pada masa depan dengan pergi ke \"Tambah token\" di dalam menu pilihan akaun anda." }, - "recipientAddressPlaceholder": { - "message": "Cari, alamat awam (0x), atau ENS" - }, "reject": { "message": "Tolak" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 56c05ffd958c..854c191c8539 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -529,9 +529,6 @@ "readdToken": { "message": "Du kan legge til dette tokenet igjen i fremtiden ved å gå til \"Legg til token\" i menyen for kontoalternativer." }, - "recipientAddressPlaceholder": { - "message": "Søk, offentlig adresse (0x) eller ENS" - }, "reject": { "message": "Avslå" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index debc2d35640a..64ebc5a7d1f2 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -1013,9 +1013,6 @@ "receive": { "message": "Tumanggap" }, - "recipientAddressPlaceholder": { - "message": "Maghanap, pampublikong address (0x), o ENS" - }, "recoveryPhraseReminderBackupStart": { "message": "Magsimula rito" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index dbc986a194e4..e3b8e50acd60 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -539,9 +539,6 @@ "readdToken": { "message": "Możesz później ponownie dodać ten token poprzez \"Dodaj token\" w opcjach menu swojego konta." }, - "recipientAddressPlaceholder": { - "message": "Szukaj, adres publiczny (0x) lub ENS" - }, "reject": { "message": "Odrzuć" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 3a930315bcbc..15ea173cba64 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Receber" }, - "recipientAddressPlaceholder": { - "message": "Insira o endereço público (0x) ou o nome ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Insira o endereço público (0x) ou nome do domínio" - }, "recommendedGasLabel": { "message": "Recomendado" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index a4b211bb0529..16662a57f07c 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -1566,9 +1566,6 @@ "receive": { "message": "Receber" }, - "recipientAddressPlaceholder": { - "message": "Busca, endereço público (0x) ou ENS" - }, "recommendedGasLabel": { "message": "Recomendado" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index a7f916825e57..906ee4f19184 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -532,9 +532,6 @@ "readdToken": { "message": "Puteți adăuga din nou acest indicativ în viitor accesând „Adăugați indicativ” din meniul de opțiuni al contului dvs." }, - "recipientAddressPlaceholder": { - "message": "Căutare, adresa publică (0x) sau ENS" - }, "reject": { "message": "Respingeți" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index f3f948d9a84e..6a2389de53cd 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Получить" }, - "recipientAddressPlaceholder": { - "message": "Введите публичный адрес (0x) или имя ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Введите публичный адрес (0x) или имя домена" - }, "recommendedGasLabel": { "message": "Рекомендовано" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 79a185cf896c..4d21a69a280f 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -517,9 +517,6 @@ "readdToken": { "message": "Tento token můžete v budoucnu přidat zpět s „Přidat token“ v nastavení účtu." }, - "recipientAddressPlaceholder": { - "message": "Vyhľadávať verejnú adresu (0x) alebo ENS" - }, "reject": { "message": "Odmítnout" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 64e7c5662c3c..d46a56707fe9 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -533,9 +533,6 @@ "readdToken": { "message": "Ta žeton lahko dodate tudi kasneje z uporabo gumba “Dodaj žeton” v možnostih vašega računa." }, - "recipientAddressPlaceholder": { - "message": "Iskanje, javni naslov (0x) ali ENS" - }, "reject": { "message": "Zavrni" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 1741b7567833..0f4dfeab00f6 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -536,9 +536,6 @@ "readdToken": { "message": "U budućnosti možete vratiti ovaj token tako što ćete otvoriti „Dodaj token“ u meniju opcija vašeg naloga." }, - "recipientAddressPlaceholder": { - "message": "Pretraga, javna adresa (0x) ili ENS" - }, "reject": { "message": "Одбиј" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index df3766108437..f9b3da4891cf 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -529,9 +529,6 @@ "readdToken": { "message": "Du kan lägga till denna token i framtiden genom att välja \"Lägg till token\" i kontots alternativmeny." }, - "recipientAddressPlaceholder": { - "message": "Sök, allmän adress (0x) eller ENS" - }, "reject": { "message": "Avvisa" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 7eb535bee573..def606c3a1ca 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -523,9 +523,6 @@ "readdToken": { "message": "Unaweza kuongeza tena kianzio hiki hapo baadaye kwa kwenda kwenye \"Ongeza kianzio\" kwenye machaguo yako ya menyu ya akaunti." }, - "recipientAddressPlaceholder": { - "message": "Tafuta, anwani za umma (0x), au ENS" - }, "reject": { "message": "Kataa" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 7eecf1acfd13..8c0573c338e8 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Tumanggap" }, - "recipientAddressPlaceholder": { - "message": "Ilagay ang pampublikong address (0x) o ENS name" - }, - "recipientAddressPlaceholderFlask": { - "message": "Ilagay ang pampublikong address (0x) o pangalan ng domain" - }, "recommendedGasLabel": { "message": "Nirekomenda" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index cc40ce53b487..adccdc2d5752 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Al" }, - "recipientAddressPlaceholder": { - "message": "Genel adres (0x) veya ENS adı girin" - }, - "recipientAddressPlaceholderFlask": { - "message": "Genel adres (0x) veya alan adı girin" - }, "recommendedGasLabel": { "message": "Önerilen" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index 59bb0b477008..a989977a3561 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -545,9 +545,6 @@ "readdToken": { "message": "Ви можете знову додати цей токен у меню облікового запису у розділі “Додати токен”. " }, - "recipientAddressPlaceholder": { - "message": "Пошук, публічна адреса (0x), або ENS" - }, "reject": { "message": "Відхилити" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index c4795a502a7e..81067ceb67d4 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "Nhận" }, - "recipientAddressPlaceholder": { - "message": "Nhập địa chỉ công khai (0x) hoặc tên ENS" - }, - "recipientAddressPlaceholderFlask": { - "message": "Nhập địa chỉ công khai (0x) hoặc tên miền" - }, "recommendedGasLabel": { "message": "Được đề xuất" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index c834c8a18230..883a65447a30 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -4162,12 +4162,6 @@ "receive": { "message": "收款" }, - "recipientAddressPlaceholder": { - "message": "输入公钥 (0x) 或 ENS 名称" - }, - "recipientAddressPlaceholderFlask": { - "message": "输入公钥 (0x) 或域名" - }, "recommendedGasLabel": { "message": "建议" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 83c0fc09e565..5acd2113329c 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -1005,9 +1005,6 @@ "receive": { "message": "接收" }, - "recipientAddressPlaceholder": { - "message": "搜尋、公開位址 (0x)、或 ENS" - }, "reject": { "message": "拒絕" }, diff --git a/shared/modules/hexstring-utils.test.js b/shared/modules/hexstring-utils.test.js index 74e444437310..9bfeac1978e1 100644 --- a/shared/modules/hexstring-utils.test.js +++ b/shared/modules/hexstring-utils.test.js @@ -1,7 +1,50 @@ import { toChecksumAddress } from 'ethereumjs-util'; -import { isValidHexAddress } from './hexstring-utils'; +import { isValidHexAddress, isPossibleAddress } from './hexstring-utils'; describe('hexstring utils', function () { + describe('isPossibleAddress', function () { + it('should allow 40-char non-prefixed hex', function () { + const address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b825'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(true); + }); + it('should allow 42-char prefixed hex', function () { + const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(true); + }); + it('should not allow 42-char prefixed non-hex', function () { + const address = '0xzzzz65c8e26263f6d9a1b5de9555d2931a33b825'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(false); + }); + it('should not allow 40-char non-prefixed non-hex', function () { + const address = 'zzzz65c8e26263f6d9a1b5de9555d2931a33b825'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(false); + }); + it('should not allow shorter prefixed hex strings', function () { + const address = '0x1234'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(false); + }); + it('should not allow shorter non-prefixed hex strings', function () { + const address = '1234'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(false); + }); + it('should not allow longer prefixed hex strings', function () { + const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825fdea65c8e262'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(false); + }); + it('should not allow longer non-prefixed hex strings', function () { + const address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b825fdea65c8e262'; + const result = isPossibleAddress(address); + expect(result).toStrictEqual(false); + }); + }); + describe('isValidHexAddress', function () { it('should allow 40-char non-prefixed hex', function () { const address = 'fdea65c8e26263f6d9a1b5de9555d2931a33b825'; diff --git a/shared/modules/hexstring-utils.ts b/shared/modules/hexstring-utils.ts index b81dc1303f9c..84b052716738 100644 --- a/shared/modules/hexstring-utils.ts +++ b/shared/modules/hexstring-utils.ts @@ -66,6 +66,16 @@ export function isValidHexAddress( return isValidAddress(addressToCheck); } +/** + * Determines if a string is a possible ethereum address + * + * @param candidate - the input to check + * @returns true if the input is a 40 char hex string with optional 0x prefix, false otherwise + */ +export function isPossibleAddress(candidate: string) { + return /^(0x)?[0-9a-fA-F]{40}$/iu.test(candidate); +} + export function toChecksumHexAddress(address: string) { if (!address) { // our internal checksumAddress function that this method replaces would diff --git a/test/e2e/tests/account/import-flow.spec.js b/test/e2e/tests/account/import-flow.spec.js index 3c05131090cc..045600cff4f4 100644 --- a/test/e2e/tests/account/import-flow.spec.js +++ b/test/e2e/tests/account/import-flow.spec.js @@ -132,7 +132,7 @@ describe('Import flow @no-mmi', function () { await locateAccountBalanceDOM(driver, ganacheServer); await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); await driver.fill('input[placeholder="0"]', '1'); diff --git a/test/e2e/tests/account/metamask-responsive-ui.spec.js b/test/e2e/tests/account/metamask-responsive-ui.spec.js index d9e9aa2f965c..ab36b863d860 100644 --- a/test/e2e/tests/account/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/account/metamask-responsive-ui.spec.js @@ -132,7 +132,7 @@ describe('MetaMask Responsive UI', function () { // starts to send a transaction await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); diff --git a/test/e2e/tests/network/network-error.spec.js b/test/e2e/tests/network/network-error.spec.js index 02514f19718c..4d45734edf77 100644 --- a/test/e2e/tests/network/network-error.spec.js +++ b/test/e2e/tests/network/network-error.spec.js @@ -60,7 +60,7 @@ describe('Gas API fallback', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); diff --git a/test/e2e/tests/petnames/petnames-transactions.spec.js b/test/e2e/tests/petnames/petnames-transactions.spec.js index ed8115da4a0c..cc19e44a55eb 100644 --- a/test/e2e/tests/petnames/petnames-transactions.spec.js +++ b/test/e2e/tests/petnames/petnames-transactions.spec.js @@ -22,7 +22,7 @@ async function createDappSendTransaction(driver) { async function createWalletSendTransaction(driver, recipientAddress) { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', recipientAddress, ); diff --git a/test/e2e/tests/settings/change-language.spec.ts b/test/e2e/tests/settings/change-language.spec.ts index 578c27be84f6..aafb36059c9b 100644 --- a/test/e2e/tests/settings/change-language.spec.ts +++ b/test/e2e/tests/settings/change-language.spec.ts @@ -145,7 +145,11 @@ describe('Settings - general tab @no-mmi', function (this: Suite) { await changeLanguage(driver, languageIndex); await driver.navigate(); await driver.clickElement(selectors.ethOverviewSend); - await driver.fill(selectors.ensInput, 'test'); + await driver.pasteIntoField( + selectors.ensInput, + // use wrong checksum address; other inputs don't show error until snaps name-lookup has happened + '0xAAAA6BF26964aF9D7eEd9e03E53415D37aA96045', + ); // Validate the language change is reflected in the dialog message const isDialogMessageChanged = await driver.isElementPresent( diff --git a/test/e2e/tests/swap-send/swap-send-test-utils.ts b/test/e2e/tests/swap-send/swap-send-test-utils.ts index c5f4d8bb3d9c..e029824f0351 100644 --- a/test/e2e/tests/swap-send/swap-send-test-utils.ts +++ b/test/e2e/tests/swap-send/swap-send-test-utils.ts @@ -21,7 +21,7 @@ export class SwapSendPage { fillRecipientAddressInput = async (address: string) => { await this.driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', address, ); }; diff --git a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js index a5ae0fea449e..0810b9c08e3f 100644 --- a/test/e2e/tests/tokens/custom-token-send-transfer.spec.js +++ b/test/e2e/tests/tokens/custom-token-send-transfer.spec.js @@ -36,7 +36,7 @@ describe('Transfer custom tokens @no-mmi', function () { await driver.delay(500); await driver.clickElement('[data-testid="eth-overview-send"]'); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', recipientAddress, ); await driver.waitForSelector({ diff --git a/test/e2e/tests/tokens/nft/send-nft.spec.js b/test/e2e/tests/tokens/nft/send-nft.spec.js index 37b81eca6794..e7f8681172e9 100644 --- a/test/e2e/tests/tokens/nft/send-nft.spec.js +++ b/test/e2e/tests/tokens/nft/send-nft.spec.js @@ -30,7 +30,7 @@ describe('Send NFT', function () { // TODO: Update Test when Multichain Send Flow is added await driver.clickElement({ text: 'Send', tag: 'button' }); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0xc427D562164062a23a5cFf596A4a3208e72Acd28', ); await driver.clickElement({ @@ -104,7 +104,7 @@ describe('Send NFT', function () { await driver.clickElement({ text: 'Send', tag: 'button' }); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0xc427D562164062a23a5cFf596A4a3208e72Acd28', ); @@ -171,7 +171,7 @@ describe('Send NFT', function () { await driver.clickElement({ text: 'Send', tag: 'button' }); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0xc427D562164062a23a5cFf596A4a3208e72Acd28', ); diff --git a/test/e2e/tests/tokens/send-erc20-to-contract.spec.js b/test/e2e/tests/tokens/send-erc20-to-contract.spec.js index a07bdea9bfdc..6e94b6377e67 100644 --- a/test/e2e/tests/tokens/send-erc20-to-contract.spec.js +++ b/test/e2e/tests/tokens/send-erc20-to-contract.spec.js @@ -36,7 +36,7 @@ describe('Send ERC20 token to contract address', function () { // Type contract address await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', contractAddress, ); diff --git a/test/e2e/tests/transaction/gas-estimates.spec.js b/test/e2e/tests/transaction/gas-estimates.spec.js index c4ce94ee9631..263dfc85d904 100644 --- a/test/e2e/tests/transaction/gas-estimates.spec.js +++ b/test/e2e/tests/transaction/gas-estimates.spec.js @@ -30,7 +30,7 @@ describe('Gas estimates generated by MetaMask', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -72,7 +72,7 @@ describe('Gas estimates generated by MetaMask', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -111,7 +111,7 @@ describe('Gas estimates generated by MetaMask', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -145,7 +145,7 @@ describe('Gas estimates generated by MetaMask', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -191,7 +191,7 @@ describe('Gas estimates generated by MetaMask', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -220,7 +220,7 @@ describe('Gas estimates generated by MetaMask', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); diff --git a/test/e2e/tests/transaction/send-eth.spec.js b/test/e2e/tests/transaction/send-eth.spec.js index 5c49bba0cf4e..36872115dcbe 100644 --- a/test/e2e/tests/transaction/send-eth.spec.js +++ b/test/e2e/tests/transaction/send-eth.spec.js @@ -27,7 +27,7 @@ describe('Send ETH', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -110,7 +110,7 @@ describe('Send ETH', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); @@ -172,7 +172,7 @@ describe('Send ETH', function () { await driver.clickElement('[data-testid="eth-overview-send"]'); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', contractAddress, ); @@ -442,7 +442,7 @@ describe('Send ETH', function () { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0xc427D562164062a23a5cFf596A4a3208e72Acd28', ); diff --git a/test/e2e/tests/transaction/send-hex-address.spec.js b/test/e2e/tests/transaction/send-hex-address.spec.js index 6adb6b5f9f6c..d93f1a0d5484 100644 --- a/test/e2e/tests/transaction/send-hex-address.spec.js +++ b/test/e2e/tests/transaction/send-hex-address.spec.js @@ -27,7 +27,7 @@ describe('Send ETH to a 40 character hexadecimal address', function () { await openActionMenuAndStartSendFlow(driver); // Paste address without hex prefix await driver.pasteIntoField( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', nonHexPrefixedAddress, ); await driver.findElement({ @@ -72,7 +72,7 @@ describe('Send ETH to a 40 character hexadecimal address', function () { await openActionMenuAndStartSendFlow(driver); // Type address without hex prefix await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', nonHexPrefixedAddress, ); await driver.findElement({ @@ -130,7 +130,7 @@ describe('Send ERC20 to a 40 character hexadecimal address', function () { await driver.clickElement('[data-testid="coin-overview-send"]'); // Paste address without hex prefix await driver.pasteIntoField( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', nonHexPrefixedAddress, ); await driver.findElement({ @@ -192,7 +192,7 @@ describe('Send ERC20 to a 40 character hexadecimal address', function () { // Type address without hex prefix await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', nonHexPrefixedAddress, ); await driver.findElement({ diff --git a/test/e2e/user-actions-benchmark.js b/test/e2e/user-actions-benchmark.js index 515764b6259b..5a851c59d61f 100644 --- a/test/e2e/user-actions-benchmark.js +++ b/test/e2e/user-actions-benchmark.js @@ -73,7 +73,7 @@ async function confirmTx() { await openActionMenuAndStartSendFlow(driver); await driver.fill( - 'input[placeholder="Enter public address (0x) or ENS name"]', + 'input[placeholder="Enter public address (0x) or domain name"]', '0x2f318C334780961FB129D2a6c30D0763d9a5C970', ); diff --git a/ui/components/multichain/pages/send/__snapshots__/send.test.js.snap b/ui/components/multichain/pages/send/__snapshots__/send.test.js.snap index 7d7ed8e0c131..7d05e9d44a0b 100644 --- a/ui/components/multichain/pages/send/__snapshots__/send.test.js.snap +++ b/ui/components/multichain/pages/send/__snapshots__/send.test.js.snap @@ -178,7 +178,7 @@ exports[`SendPage render and initialization should render correctly even when a class="ens-input__wrapper__input" data-testid="ens-input" dir="auto" - placeholder="Enter public address (0x) or ENS name" + placeholder="Enter public address (0x) or domain name" spellcheck="false" type="text" value="" diff --git a/ui/components/multichain/pages/send/send.test.js b/ui/components/multichain/pages/send/send.test.js index 164fe2b8bb3c..cdba904090b2 100644 --- a/ui/components/multichain/pages/send/send.test.js +++ b/ui/components/multichain/pages/send/send.test.js @@ -274,7 +274,7 @@ describe('SendPage', () => { // Ensure that the send flow renders on the add recipient screen when // there is no draft transaction. expect( - getByPlaceholderText('Enter public address (0x) or ENS name'), + getByPlaceholderText('Enter public address (0x) or domain name'), ).toBeTruthy(); expect(container).toMatchSnapshot(); diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 672ee0ea4395..4627b4fe2f44 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -95,11 +95,9 @@ import { getTokenIdParam, } from '../../helpers/utils/token-util'; import { - IS_FLASK, checkExistingAddresses, isDefaultMetaMaskChain, isOriginContractAddress, - isValidDomainName, } from '../../helpers/utils/util'; import { getGasEstimateType, @@ -112,6 +110,7 @@ import { resetDomainResolution } from '../domains'; import { isBurnAddress, isValidHexAddress, + isPossibleAddress, toChecksumHexAddress, } from '../../../shared/modules/hexstring-utils'; import { isSmartContractAddress } from '../../helpers/utils/transactions.util'; @@ -1607,11 +1606,10 @@ const slice = createSlice({ if ( isBurnAddress(state.recipientInput) || - (!isValidHexAddress(state.recipientInput, { - mixedCaseUseChecksum: true, - }) && - !IS_FLASK && - !isValidDomainName(state.recipientInput)) + (isPossibleAddress(state.recipientInput) && + !isValidHexAddress(state.recipientInput, { + mixedCaseUseChecksum: true, + })) ) { draftTransaction.recipient.error = isDefaultMetaMaskChain(chainId) ? INVALID_RECIPIENT_ADDRESS_ERROR diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 70ca9cde62c7..0a19623db066 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -768,7 +768,7 @@ describe('Send Slice', () => { it('should error with an invalid address error when user input is not a valid hex string', () => { const tokenAssetTypeState = { ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, - recipientInput: '0xValidateError', + recipientInput: '0xAAAA6BF26964aF9D7eEd9e03E53415D37aA96045', }; const action = { type: 'send/validateRecipientUserInput', @@ -793,7 +793,7 @@ describe('Send Slice', () => { it('should error with an invalid network error when user input is not a valid hex string on a non default network', () => { const tokenAssetTypeState = { ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, - recipientInput: '0xValidateError', + recipientInput: '0xAAAA6BF26964aF9D7eEd9e03E53415D37aA96045', }; const action = { type: 'send/validateRecipientUserInput', diff --git a/ui/pages/confirmations/send/send-content/add-recipient/domain-input.component.js b/ui/pages/confirmations/send/send-content/add-recipient/domain-input.component.js index 5eef93681a3c..0b2514f12414 100644 --- a/ui/pages/confirmations/send/send-content/add-recipient/domain-input.component.js +++ b/ui/pages/confirmations/send/send-content/add-recipient/domain-input.component.js @@ -4,11 +4,7 @@ import classnames from 'classnames'; import { isHexString } from '@metamask/utils'; import { addHexPrefix } from '../../../../../../app/scripts/lib/util'; -import { - IS_FLASK, - isValidDomainName, - shortenAddress, -} from '../../../../../helpers/utils/util'; +import { shortenAddress } from '../../../../../helpers/utils/util'; import { isBurnAddress, isValidHexAddress, @@ -87,9 +83,7 @@ export default class DomainInput extends Component { return null; } - if ((IS_FLASK && !isHexString(input)) || isValidDomainName(input)) { - lookupDomainName(input); - } else { + if (isHexString(input)) { resetDomainResolution(); if ( onValidAddressTyped && @@ -98,6 +92,8 @@ export default class DomainInput extends Component { ) { onValidAddressTyped(addHexPrefix(input)); } + } else { + lookupDomainName(input); } return null; @@ -167,11 +163,7 @@ export default class DomainInput extends Component { className="ens-input__wrapper__input" type="text" dir="auto" - placeholder={ - IS_FLASK - ? t('recipientAddressPlaceholderFlask') - : t('recipientAddressPlaceholder') - } + placeholder={t('recipientAddressPlaceholderNew')} onChange={this.onChange} onPaste={this.onPaste} spellCheck="false" From 9221f8ef2e68dde785c1e27e52781418ce087178 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 16 Oct 2024 13:14:34 +0200 Subject: [PATCH 18/46] chore: Update RC hotfix changelog (#27900) ## **Description** Updates the hotfix RC changelog to mention the PR that was picked into the RC. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a2274c06810..5cb765a12f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [12.4.2] +### Fixed +- Fix a problem where certain name lookup Snaps would not be triggered ([#27880](https://github.com/MetaMask/metamask-extension/pull/27880)) ## [12.4.1] ### Fixed From 36fe5a8bd4f9e77b3851adade4b9d9adfa3af0b5 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 16 Oct 2024 09:11:07 -0230 Subject: [PATCH 19/46] chore: Cherry pick f523617a9 to v12.4.2 (#27899) Cherry picks f523617a9 (https://github.com/MetaMask/metamask-extension/pull/27856) to v12.4.2 RC branch Co-authored-by: Frederik Bolding --- .yarnrc.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.yarnrc.yml b/.yarnrc.yml index 7176c6152327..fb335f532861 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -120,15 +120,9 @@ npmAuditIgnoreAdvisories: # upon old versions of ethereumjs-utils. - 'ethereum-cryptography (deprecation)' - # Currently only dependent on deprecated @metamask/types as it is brought in - # by @metamask/keyring-api. Updating the dependency in keyring-api will - # remove this. - - '@metamask/types (deprecation)' - - # @metamask/keyring-api also depends on @metamask/snaps-ui which is - # deprecated. Replacing that dependency with @metamask/snaps-sdk will remove - # this. - - '@metamask/snaps-ui (deprecation)' + # Currently in use for the network list drag and drop functionality. + # Maintenance has stopped and the project will be archived in 2025. + - 'react-beautiful-dnd (deprecation)' npmRegistries: 'https://npm.pkg.github.com': From 6ec1ce9253ae6fba44fc9cf64e5fe2f23586717b Mon Sep 17 00:00:00 2001 From: HJetpoluru Date: Thu, 17 Oct 2024 14:44:45 -0400 Subject: [PATCH 20/46] Fixed dulipcates, required changes for test and changelog --- CHANGELOG.md | 4 ++-- ui/ducks/send/send.js | 1 + ui/ducks/send/send.test.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92897f56f756..8cb9e4f10e7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [12.5.0] + ## [12.4.2] ### Fixed - Fix a problem where certain name lookup Snaps would not be triggered ([#27880](https://github.com/MetaMask/metamask-extension/pull/27880)) @@ -5150,8 +5151,7 @@ Update styles and spacing on the critical error page ([#20350](https://github.c [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.5.0...HEAD -[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.4.1...v12.5.0 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v12.4.2...HEAD +[12.5.0]: https://github.com/MetaMask/metamask-extension/compare/v12.4.2...v12.5.0 [12.4.2]: https://github.com/MetaMask/metamask-extension/compare/v12.4.1...v12.4.2 [12.4.1]: https://github.com/MetaMask/metamask-extension/compare/v12.4.0...v12.4.1 [12.4.0]: https://github.com/MetaMask/metamask-extension/compare/v12.3.1...v12.4.0 diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index cdbe7d2daa86..fb3153d74c93 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -109,6 +109,7 @@ import { isBurnAddress, isPossibleAddress, isValidHexAddress, + isPossibleAddress, toChecksumHexAddress, } from '../../../shared/modules/hexstring-utils'; import { isSmartContractAddress } from '../../helpers/utils/transactions.util'; diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index cdb6e3ad7e94..59a32c581e0d 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -768,7 +768,7 @@ describe('Send Slice', () => { it('should not error with an invalid address error when user input is not a valid hex string', () => { const tokenAssetTypeState = { ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, - recipientInput: '0xValidateError', + recipientInput: '0xAAAA6BF26964aF9D7eEd9e03E53415D37aA96045', }; const action = { type: 'send/validateRecipientUserInput', From 9f77f8fc31451537a9b39928be65b224731b30fa Mon Sep 17 00:00:00 2001 From: HJetpoluru Date: Thu, 17 Oct 2024 14:46:47 -0400 Subject: [PATCH 21/46] Fixed the test --- ui/ducks/send/send.js | 1 - ui/ducks/send/send.test.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index fb3153d74c93..cdbe7d2daa86 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -109,7 +109,6 @@ import { isBurnAddress, isPossibleAddress, isValidHexAddress, - isPossibleAddress, toChecksumHexAddress, } from '../../../shared/modules/hexstring-utils'; import { isSmartContractAddress } from '../../helpers/utils/transactions.util'; diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 59a32c581e0d..cdb6e3ad7e94 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -768,7 +768,7 @@ describe('Send Slice', () => { it('should not error with an invalid address error when user input is not a valid hex string', () => { const tokenAssetTypeState = { ...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, - recipientInput: '0xAAAA6BF26964aF9D7eEd9e03E53415D37aA96045', + recipientInput: '0xValidateError', }; const action = { type: 'send/validateRecipientUserInput', From a3cf5f7597e553e9ab8e5d0acfbe02b688fccda1 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 17 Oct 2024 22:31:56 -0230 Subject: [PATCH 22/46] fix (cherry-pick): bump `@metamask/ppom-validator` from `0.34.0` to `0.35.1` (#27939) (#27944) Cherry-picks https://github.com/MetaMask/metamask-extension/pull/27939 (9716e94) to v12.5.0 --------- Co-authored-by: cryptodev-2s <109512101+cryptodev-2s@users.noreply.github.com> Co-authored-by: MetaMask Bot --- lavamoat/browserify/beta/policy.json | 46 ++------------------------- lavamoat/browserify/flask/policy.json | 46 ++------------------------- lavamoat/browserify/main/policy.json | 46 ++------------------------- lavamoat/browserify/mmi/policy.json | 46 ++------------------------- package.json | 2 +- yarn.lock | 35 ++++++-------------- 6 files changed, 19 insertions(+), 202 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index bf47338c68a1..0ce8a5ab4899 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1943,57 +1943,15 @@ "crypto": true }, "packages": { + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/ppom-validator>@metamask/base-controller": true, - "@metamask/ppom-validator>@metamask/controller-utils": true, "@metamask/ppom-validator>crypto-js": true, "@metamask/ppom-validator>elliptic": true, - "@metamask/rpc-errors": true, "await-semaphore": true, "browserify>buffer": true } }, - "@metamask/ppom-validator>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/ppom-validator>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "@metamask/ppom-validator>@metamask/utils": true, - "bn.js": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true - } - }, - "@metamask/ppom-validator>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/ppom-validator>crypto-js": { "globals": { "crypto": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index bf47338c68a1..0ce8a5ab4899 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1943,57 +1943,15 @@ "crypto": true }, "packages": { + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/ppom-validator>@metamask/base-controller": true, - "@metamask/ppom-validator>@metamask/controller-utils": true, "@metamask/ppom-validator>crypto-js": true, "@metamask/ppom-validator>elliptic": true, - "@metamask/rpc-errors": true, "await-semaphore": true, "browserify>buffer": true } }, - "@metamask/ppom-validator>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/ppom-validator>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "@metamask/ppom-validator>@metamask/utils": true, - "bn.js": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true - } - }, - "@metamask/ppom-validator>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/ppom-validator>crypto-js": { "globals": { "crypto": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index bf47338c68a1..0ce8a5ab4899 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1943,57 +1943,15 @@ "crypto": true }, "packages": { + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/ppom-validator>@metamask/base-controller": true, - "@metamask/ppom-validator>@metamask/controller-utils": true, "@metamask/ppom-validator>crypto-js": true, "@metamask/ppom-validator>elliptic": true, - "@metamask/rpc-errors": true, "await-semaphore": true, "browserify>buffer": true } }, - "@metamask/ppom-validator>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/ppom-validator>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "@metamask/ppom-validator>@metamask/utils": true, - "bn.js": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true - } - }, - "@metamask/ppom-validator>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/ppom-validator>crypto-js": { "globals": { "crypto": true, diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 54d61c2e245c..f8cd1fdfca54 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -2035,57 +2035,15 @@ "crypto": true }, "packages": { + "@metamask/base-controller": true, + "@metamask/controller-utils": true, "@metamask/eth-query>json-rpc-random-id": true, - "@metamask/ppom-validator>@metamask/base-controller": true, - "@metamask/ppom-validator>@metamask/controller-utils": true, "@metamask/ppom-validator>crypto-js": true, "@metamask/ppom-validator>elliptic": true, - "@metamask/rpc-errors": true, "await-semaphore": true, "browserify>buffer": true } }, - "@metamask/ppom-validator>@metamask/base-controller": { - "globals": { - "setTimeout": true - }, - "packages": { - "immer": true - } - }, - "@metamask/ppom-validator>@metamask/controller-utils": { - "globals": { - "URL": true, - "console.error": true, - "fetch": true, - "setTimeout": true - }, - "packages": { - "@ethereumjs/tx>@ethereumjs/util": true, - "@metamask/controller-utils>@spruceid/siwe-parser": true, - "@metamask/ethjs>@metamask/ethjs-unit": true, - "@metamask/ppom-validator>@metamask/utils": true, - "bn.js": true, - "browserify>buffer": true, - "eslint>fast-deep-equal": true, - "eth-ens-namehash": true - } - }, - "@metamask/ppom-validator>@metamask/utils": { - "globals": { - "TextDecoder": true, - "TextEncoder": true - }, - "packages": { - "@metamask/utils>@metamask/superstruct": true, - "@metamask/utils>@scure/base": true, - "@metamask/utils>pony-cause": true, - "@noble/hashes": true, - "browserify>buffer": true, - "nock>debug": true, - "semver": true - } - }, "@metamask/ppom-validator>crypto-js": { "globals": { "crypto": true, diff --git a/package.json b/package.json index 82592d8b0d45..f1b3fc502664 100644 --- a/package.json +++ b/package.json @@ -343,7 +343,7 @@ "@metamask/permission-log-controller": "^2.0.1", "@metamask/phishing-controller": "^12.0.1", "@metamask/post-message-stream": "^8.0.0", - "@metamask/ppom-validator": "0.34.0", + "@metamask/ppom-validator": "0.35.1", "@metamask/preinstalled-example-snap": "^0.1.0", "@metamask/profile-sync-controller": "^0.9.7", "@metamask/providers": "^14.0.2", diff --git a/yarn.lock b/yarn.lock index 36c6e53aed30..8e842fb9c927 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4993,21 +4993,6 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^8.0.1": - version: 8.0.4 - resolution: "@metamask/controller-utils@npm:8.0.4" - dependencies: - "@ethereumjs/util": "npm:^8.1.0" - "@metamask/eth-query": "npm:^4.0.0" - "@metamask/ethjs-unit": "npm:^0.3.0" - "@metamask/utils": "npm:^8.3.0" - "@spruceid/siwe-parser": "npm:1.1.3" - eth-ens-namehash: "npm:^2.0.8" - fast-deep-equal: "npm:^3.1.3" - checksum: 10/112a07614eec28cff270c99aa0695bec34cd29461d0c4cb83eb913a5bc37b3b72e4f33dad59a0ab23da5d1b091372ee5207657349bfdb814098c5a51d6570554 - languageName: node - linkType: hard - "@metamask/design-tokens@npm:^1.12.0": version: 1.13.0 resolution: "@metamask/design-tokens@npm:1.13.0" @@ -6026,21 +6011,21 @@ __metadata: languageName: node linkType: hard -"@metamask/ppom-validator@npm:0.34.0": - version: 0.34.0 - resolution: "@metamask/ppom-validator@npm:0.34.0" +"@metamask/ppom-validator@npm:0.35.1": + version: 0.35.1 + resolution: "@metamask/ppom-validator@npm:0.35.1" dependencies: - "@metamask/base-controller": "npm:^6.0.2" - "@metamask/controller-utils": "npm:^8.0.1" - "@metamask/network-controller": "npm:^20.0.0" - "@metamask/rpc-errors": "npm:^6.3.1" - "@metamask/utils": "npm:^8.3.0" + "@metamask/base-controller": "npm:^7.0.1" + "@metamask/controller-utils": "npm:^11.3.0" + "@metamask/utils": "npm:^9.2.1" await-semaphore: "npm:^0.1.3" crypto-js: "npm:^4.2.0" elliptic: "npm:^6.5.4" eslint-plugin-n: "npm:^16.6.2" json-rpc-random-id: "npm:^1.0.1" - checksum: 10/140b2070ddf4a9d7d13518ab1a10aa71961715434053096d0caa6f4ce104bbcaea5f5152edfa9b6c42f9bc929116afbb6a0542c1147e3101d04ef29bcf7a6c9f + peerDependencies: + "@metamask/network-controller": ^21.0.0 + checksum: 10/3dd37ced473a78e4b7847c61b6c6fb1e2ae4865dee67de9574462fd618dc5ea7be46874f12ff18383702c46c9c07c32dbac00be2e6ad26cb45a3dcc4ffa09ab7 languageName: node linkType: hard @@ -26160,7 +26145,7 @@ __metadata: "@metamask/phishing-controller": "npm:^12.0.1" "@metamask/phishing-warning": "npm:^4.0.0" "@metamask/post-message-stream": "npm:^8.0.0" - "@metamask/ppom-validator": "npm:0.34.0" + "@metamask/ppom-validator": "npm:0.35.1" "@metamask/preinstalled-example-snap": "npm:^0.1.0" "@metamask/profile-sync-controller": "npm:^0.9.7" "@metamask/providers": "npm:^14.0.2" From 7954c6dfd555fa318e3c8520594c448bc69675ee Mon Sep 17 00:00:00 2001 From: Marina Boboc <120041701+benjisclowder@users.noreply.github.com> Date: Mon, 21 Oct 2024 15:25:13 +0300 Subject: [PATCH 23/46] V12.5.0 Changelog (#27867) ## **Description** Adding 12.5.0 Changelog entries. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27867?quickstart=1) --------- Co-authored-by: Dan J Miller --- CHANGELOG.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cb9e4f10e7f..0b33f07fb3d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,79 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [12.5.0] +### Added +- New UI and functionality for adding and managing networks ([#26433](https://github.com/MetaMask/metamask-extension/pull/26433)), ([#27085](https://github.com/MetaMask/metamask-extension/pull/27085)) + - Instead of having different networks in the network list for the same chain but different RPC urls, there are now multiple selectable RPC urls per chain + - For the UI, networks are now added, edited, and deleted directly in the network list. Networks are no longer edited via the settings page. + - Users with multiple RPC endpoints per chain are shown a modal upon upgrade, allowing them to select a different endpoint as the default. + - The UI for wallet_addEthereumChain is changed, to message that users may be adding an additional endpoint to an existing network, rather than adding a new network. +- Added display of names and images for ERC721 NFTs to the simulations in transaction confirmations ([#25692](https://github.com/MetaMask/metamask-extension/pull/25692)) +- Added a modal to edit the spending cap for ERC20 approve and increase allowance ([#26845](https://github.com/MetaMask/metamask-extension/pull/26845)) +- Added a new modal to help users with zero balance buy, receive, or transfer tokens ([#26426](https://github.com/MetaMask/metamask-extension/pull/26426)) +- Add support for ENS resolution on some Layer 2 networks ([#26242](https://github.com/MetaMask/metamask-extension/pull/26242)) +- Added "Basic Functionality" to the Settings search results ([#25185](https://github.com/MetaMask/metamask-extension/pull/25185)) +- [MMI] Added MMI flow support to the new transaction confirmations view ([#26817](https://github.com/MetaMask/metamask-extension/pull/26817)) +- [MMI] Added "note to trader" functionality to the new transaction confirmation view for MMI ([#27214](https://github.com/MetaMask/metamask-extension/pull/27214)) + +### Changed +- Redesigned ERC20 Approve confirmation with a new Spending Cap section ([#26606](https://github.com/MetaMask/metamask-extension/pull/26606)) +- Update UI for switching networks via dapp for custom chain IDs ([#26905](https://github.com/MetaMask/metamask-extension/pull/26905)) +- Updated the custom UI for Snaps, including Snaps Home and Snap Custom Dialog ([#26639](https://github.com/MetaMask/metamask-extension/pull/26639)) +- Removed the scroll-to-bottom requirement for certain confirmations ([#26887](https://github.com/MetaMask/metamask-extension/pull/26887)) +- Updated the copy from "estimated fee" to "network fee ([#26859](https://github.com/MetaMask/metamask-extension/pull/26859)) +- Updated the scam token warning message to be less aggressive and include a suggested ticker symbol ([#26994](https://github.com/MetaMask/metamask-extension/pull/26994)) +- Updated the Ethereum logo to purple for better visibility in light mode ([#27295](https://github.com/MetaMask/metamask-extension/pull/27295)) +- Updated subtitles in the redesigned signature interface ([#27359](https://github.com/MetaMask/metamask-extension/pull/27359)) +- Improved performance by optimizing how token decimals are fetched and used ([#27088](https://github.com/MetaMask/metamask-extension/pull/27088)) +- Updated the Add Account button to use light theme colors in dark mode ([#26879](https://github.com/MetaMask/metamask-extension/pull/26879)) +- Updated the symbol for Q Mainnet ([#27134](https://github.com/MetaMask/metamask-extension/pull/27134)) +- Removed the use of the Roboto font to improve performance and reduce file size ([#26552](https://github.com/MetaMask/metamask-extension/pull/26552)) +- Renamed "Back up your data" to "Export your data" in the advanced settings ([#26322](https://github.com/MetaMask/metamask-extension/pull/26322)) +- Made headers and footers sticky in confirmation popups for improved UI/UX ([#26853](https://github.com/MetaMask/metamask-extension/pull/26853)) +- Updated the tooltip text and link in the swap flow to provide clearer information about gas fees ([#27261](https://github.com/MetaMask/metamask-extension/pull/27261)) +- Updated the Swaps UI to change the symbol from MATIC to POL ([#26826](https://github.com/MetaMask/metamask-extension/pull/26826)) +- Updated the threshold for the "network is busy" warning ([#26983](https://github.com/MetaMask/metamask-extension/pull/26983)) +- Updated the close icon SVG to match design specifications ([#27235](https://github.com/MetaMask/metamask-extension/pull/27235)) +- Ensured consistent confirmation navigation by selecting the oldest confirmation request by default ([#27326](https://github.com/MetaMask/metamask-extension/pull/27326)) +- Used default buttons when Snap branding is hidden and fixed footer layout issue ([#27303](https://github.com/MetaMask/metamask-extension/pull/27303)) +- Updated the UI to correctly display the origin when Snaps request other Snaps ([#26715](https://github.com/MetaMask/metamask-extension/pull/26715)) +- Moved the portfolio button next to the token price amount ([#26867](https://github.com/MetaMask/metamask-extension/pull/26867)) +- Updated the main page buttons to use light theme colors in dark mode ([#26884](https://github.com/MetaMask/metamask-extension/pull/26884)) +- [FLASK] Updated the confirmation flow to use the new SnapAuthorshipPill component for displaying snap origin ([#26881](https://github.com/MetaMask/metamask-extension/pull/26881)) +- [MMI] Updated MMI support links to the new page ([#26839](https://github.com/MetaMask/metamask-extension/pull/26839)) +- [MMI] Removed the portfolio button and fixed the receive modal for MMI ([#27286](https://github.com/MetaMask/metamask-extension/pull/27286)) + +### Fixed +- Fixed an issue with typed sign requests by updating a dependency ([#26914](https://github.com/MetaMask/metamask-extension/pull/26914)) +- Fixed an error when using non-standard currency codes in the currency conversion setting ([#27239](https://github.com/MetaMask/metamask-extension/pull/27239)) +- Fixed the asset picker to display correctly in both light and dark modes ([#27127](https://github.com/MetaMask/metamask-extension/pull/27127)) +- Fixed an issue where tokens with 0 decimals showed an incorrect balance ([#27083](https://github.com/MetaMask/metamask-extension/pull/27083)) +- Fixed an issue with default currency decimals to correctly display the maximum balance ([#27074](https://github.com/MetaMask/metamask-extension/pull/27074)) +- Fixed QR code scanning to correctly extract and populate Ethereum addresses ([#27002](https://github.com/MetaMask/metamask-extension/pull/27002)) +- Fixed an issue where the default nonce value was incorrect after switching networks between transactions ([#27297](https://github.com/MetaMask/metamask-extension/pull/27297)) +- Fixed the alignment of the spending cap label ([#27338](https://github.com/MetaMask/metamask-extension/pull/27338)) +- Fixed the issue where the confirm button was disabled for contract interactions with Ledger accounts ([#27331](https://github.com/MetaMask/metamask-extension/pull/27331)) +- Fixed estimated fee calculations in redesigned screens by converting fee values to the correct units ([#27247](https://github.com/MetaMask/metamask-extension/pull/27247)) +- Improved gas limit accuracy by using values from the gas estimation API ([#27165](https://github.com/MetaMask/metamask-extension/pull/27165)) +- Fixed an issue where toggling off "Decode smart contracts" prevented ERC20 approvals ([#27203](https://github.com/MetaMask/metamask-extension/pull/27203)) +- Fixed incomplete transactions on startup to prevent alerts and blocking subsequent transactions ([#26963](https://github.com/MetaMask/metamask-extension/pull/26963)) +- Fixed the visibility of fiat values on test networks based on user settings ([#26273](https://github.com/MetaMask/metamask-extension/pull/26273)) +- Fixed the display of network names in the network switch toast on confirmation pages ([#27100](https://github.com/MetaMask/metamask-extension/pull/27100)) +- Fixed the visibility of the edit button on the confirmation page for sending ERC-1155 tokens ([#27004](https://github.com/MetaMask/metamask-extension/pull/27004)) +- Fixed an issue to allow signing type signature requests with Cosmos ([#27021](https://github.com/MetaMask/metamask-extension/pull/27021)) +- Fixed the width of confirmation pages in the expanded extension view ([#26965](https://github.com/MetaMask/metamask-extension/pull/26965)) +- Fixed a bug in calculating token value for tokens with a large number of decimals ([#26931](https://github.com/MetaMask/metamask-extension/pull/26931)) +- Fixed the nonce increment/decrement functionality using arrow buttons ([#26569](https://github.com/MetaMask/metamask-extension/pull/26569)) +- Improved performance by preloading the English messages.json file ([#26556](https://github.com/MetaMask/metamask-extension/pull/26556)) +- Applied performance, analytics, and bug fixes for account syncing ([#27534](https://github.com/MetaMask/metamask-extension/pull/27534)), ([#27330](https://github.com/MetaMask/metamask-extension/pull/27330)) +- Fixed the gap between custom UI boxes in Snaps to be 16px for the root and 8px for children ([#27405](https://github.com/MetaMask/metamask-extension/pull/27405)) +- Removed the third-party notice for preinstalled Snaps ([#27319](https://github.com/MetaMask/metamask-extension/pull/27319)) +- Fixed padding issue for the root element in Snaps UI, regardless of its type ([#26850](https://github.com/MetaMask/metamask-extension/pull/26850)) +- Fixed an issue where the Data Collection setting did not appear in search results ([#26953](https://github.com/MetaMask/metamask-extension/pull/26953)) +- Fixed the Account List Menu to hide the back button by default ([#26940](https://github.com/MetaMask/metamask-extension/pull/26940)) +- Fixed sticky footer UI issue on Snaps Home Page in extended view ([#27799](https://github.com/MetaMask/metamask-extension/pull/27799)) +- Fixed an issue with Snaps to correctly block phishing URLs ([#27817](https://github.com/MetaMask/metamask-extension/pull/27817)) +- Updated account sync to fix an issue with saving imported accounts ([#27749](https://github.com/MetaMask/metamask-extension/pull/27749)) ## [12.4.2] ### Fixed @@ -60,7 +133,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Enabled hardware wallets for smart transactions in MetaMask swaps ([#25742](https://github.com/MetaMask/metamask-extension/pull/25742)) - Added a "Close extension" button on the Smart Transaction Status Page for pending dapp transactions ([#25965](https://github.com/MetaMask/metamask-extension/pull/25965)) - Added a toast message to notify users if they quickly send transactions on different networks ([#26114](https://github.com/MetaMask/metamask-extension/pull/26114)) -- Enabled token auto-detection by default ([#26406](https://github.com/MetaMask/metamask-extension/pull/26406)) +- Enabled token auto-detection by default ([#](https://github.com/MetaMask/metamask-extension/pull/26406)) ### Changed - Improve information and presentation of permit signatures, including: PermitSingle, PermitBatch, PermitTransferFrom, PermitBatchTransferFrom and TradeOrder ([#26107](https://github.com/MetaMask/metamask-extension/pull/26107)) From ab0250ec984983d3f53f963c79d02fd43a19675d Mon Sep 17 00:00:00 2001 From: Marina Boboc <120041701+benjisclowder@users.noreply.github.com> Date: Mon, 21 Oct 2024 18:17:12 +0300 Subject: [PATCH 24/46] cherry-pick: Disable account syncing prod in v12.5.0 (#27982) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-picks https://github.com/MetaMask/metamask-extension/pull/27943 ## **Description** This PR disables account syncing in prod until we have e2e tests and documentation of proper testing. There were no merge conflicts when picking these commits. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27982?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/pull/27943 ## **Manual testing steps** 1. yarn build 2. Account syncing should not occur ## **Screenshots/Recordings** ### **Before** ### **After** ## **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/develop/.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/develop/.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. Co-authored-by: Dan J Miller Co-authored-by: Mark Stacey --- app/scripts/metamask-controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ca5e3abf4985..ea8fa297cd2f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -155,6 +155,7 @@ import { NotificationServicesPushController, NotificationServicesController, } from '@metamask/notification-services-controller'; +import { isProduction } from '../../shared/modules/environment'; import { methodsRequiringNetworkSwitch } from '../../shared/constants/methods-tags'; ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) @@ -1531,7 +1532,7 @@ export default class MetamaskController extends EventEmitter { }, }, env: { - isAccountSyncingEnabled: isManifestV3, + isAccountSyncingEnabled: !isProduction() && isManifestV3, }, messenger: this.controllerMessenger.getRestricted({ name: 'UserStorageController', From 6173a139097293e63e1d832256a4baabd88ae481 Mon Sep 17 00:00:00 2001 From: Niranjana Binoy <43930900+NiranjanaBinoy@users.noreply.github.com> Date: Mon, 21 Oct 2024 11:53:38 -0400 Subject: [PATCH 25/46] test: Completing missing step for import ERC1155 token origin dapp in existing E2E test (#27680) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Adding missing Watch ERC1155 Asset step and fully cover the manual scenario [here](https://github.com/MetaMask/metamask-extension/blob/develop/test/manual-scenarios/tokens/import%20erc1155%20token%20origin%20dapp.csv) in the E2E test `test/e2e/tests/tokens/nft/erc1155-interaction.spec.js` [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27680?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/27371 ## **Manual testing steps** 1. Run `yarn test:e2e:single --browser=chrome test/e2e/tests/tokens/nft/erc1155-interaction.spec.js` 2. test should finish without failure 3. The last test run should watch asset erc1155. ## **Screenshots/Recordings** ### **Before** ### **After** ## **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/develop/.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/develop/.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. --- .../tokens/nft/erc1155-interaction.spec.js | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/e2e/tests/tokens/nft/erc1155-interaction.spec.js b/test/e2e/tests/tokens/nft/erc1155-interaction.spec.js index 1fed3946dea9..c635d465353a 100644 --- a/test/e2e/tests/tokens/nft/erc1155-interaction.spec.js +++ b/test/e2e/tests/tokens/nft/erc1155-interaction.spec.js @@ -1,4 +1,5 @@ const { strict: assert } = require('assert'); +const { mockNetworkStateOld } = require('../../../../stub/networks'); const { withFixtures, DAPP_URL, @@ -19,6 +20,15 @@ describe('ERC1155 NFTs testdapp interaction', function () { dapp: true, fixtures: new FixtureBuilder() .withPermissionControllerConnectedToTestDapp() + .withNetworkController( + mockNetworkStateOld({ + chainId: '0x539', + nickname: 'Localhost 8545', + rpcUrl: 'http://localhost:8545', + ticker: 'ETH', + blockExplorerUrl: 'https://etherscan.io/', + }), + ) .build(), ganacheOptions: defaultGanacheOptions, smartContract, @@ -59,6 +69,36 @@ describe('ERC1155 NFTs testdapp interaction', function () { css: '[data-testid="activity-list-item-action"]', text: 'Deposit', }); + await driver.clickElement('[data-testid="activity-list-item-action"]'); + await driver.clickElement({ + text: 'View on block explorer', + tag: 'a', + }); + + // Switch to block explorer + await driver.switchToWindowWithTitle('E2E Test Page'); + await driver.findElement('[data-testid="empty-page-body"]'); + // Verify block explorer + await driver.waitForUrl({ + url: 'https://etherscan.io/tx/0xfe4428397f7913875783c5c0dad182937b596148295bc33c7f08d74fdee8897f', + }); + + // switch to Dapp + await driver.switchToWindowWithTitle(WINDOW_TITLES.TestDApp); + await driver.fill('#watchAssetInput', '1'); + await driver.clickElement('#watchAssetButton'); + + await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); + await driver.clickElementAndWaitForWindowToClose( + '[data-testid="page-container-footer-next"]', + ); + await driver.switchToWindowWithTitle( + WINDOW_TITLES.ExtensionInFullScreenView, + ); + + await driver.clickElementSafe('[data-testid="popover-close"]'); + await driver.clickElement('[data-testid="account-overview__nfts-tab"]'); + await driver.clickElement('[data-testid="nft-item"]'); }, ); }); From f995e3cb193681e2186e53b1d673728eddd1202f Mon Sep 17 00:00:00 2001 From: Howard Braham Date: Mon, 21 Oct 2024 11:03:06 -0700 Subject: [PATCH 26/46] ci: reduced Sentry frequency on CircleCI develop (#27912) ## **Description** Cut in half Sentry frequency on CircleCI develop [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27912?quickstart=1) ## **Related issues** ## **Manual testing steps** ## **Screenshots/Recordings** ## **Pre-merge author checklist** ## **Pre-merge reviewer checklist** --- app/scripts/lib/setupSentry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 627f46fa79fa..1b9e9f4ddbfc 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -125,7 +125,7 @@ function getTracesSampleRate(sentryTarget) { // Report very frequently on develop branch, and never on other branches // (Unless you use a `flags = {"sentry": {"tracesSampleRate": x.xx}}` override) if (flags.circleci.branch === 'develop') { - return 0.03; + return 0.015; } return 0; } From 134d9a660d593d4add38fcfa63f4b88da9bab806 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:43:21 +0000 Subject: [PATCH 27/46] fix(deps): gridplus-sdk@2.5.1->~2.6.0 (#27973) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** - fix(deps): `gridplus-sdk@2.5.1->~2.6.0` - `2.7.0` updates to `@ethereumjs/tx` 5, so holding at 2.6 - removes dependency on legacy `ethereum-cryptography` v1 - dedupe and unpin `@ethereumjs/tx` to `^4.2.0` - `eth-lattice-keyring` is pinned to `@ethereumjs/tx@4.1.1` - `gridplus-sdk` is pinned to `@ethereumjs/tx@4.1.2` - fix(deps): bump `elliptic@6.5.4->^6.5.7` via resolutions - fix(deps): bump `secp256k` [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27973?quickstart=1) ## **Related issues** - https://github.com/GridPlus/eth-lattice-keyring/pull/64 - https://github.com/GridPlus/gridplus-sdk/issues/547 ## **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 Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. --- lavamoat/browserify/beta/policy.json | 163 +++------------- lavamoat/browserify/flask/policy.json | 163 +++------------- lavamoat/browserify/main/policy.json | 163 +++------------- lavamoat/browserify/mmi/policy.json | 163 +++------------- package.json | 18 +- yarn.lock | 266 +++++++------------------- 6 files changed, 192 insertions(+), 744 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 9cbdda6ac03e..1ec0abe0f909 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -182,16 +182,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -1498,7 +1510,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -4073,59 +4091,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4141,20 +4116,20 @@ "setTimeout": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, @@ -4171,41 +4146,6 @@ "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk>aes-js": { "globals": { "define": true @@ -4246,27 +4186,6 @@ "location": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { "TextEncoder": true @@ -4274,18 +4193,7 @@ }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4609,20 +4517,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 9cbdda6ac03e..1ec0abe0f909 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -182,16 +182,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -1498,7 +1510,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -4073,59 +4091,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4141,20 +4116,20 @@ "setTimeout": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, @@ -4171,41 +4146,6 @@ "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk>aes-js": { "globals": { "define": true @@ -4246,27 +4186,6 @@ "location": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { "TextEncoder": true @@ -4274,18 +4193,7 @@ }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4609,20 +4517,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 9cbdda6ac03e..1ec0abe0f909 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -182,16 +182,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -1498,7 +1510,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -4073,59 +4091,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4141,20 +4116,20 @@ "setTimeout": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, @@ -4171,41 +4146,6 @@ "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk>aes-js": { "globals": { "define": true @@ -4246,27 +4186,6 @@ "location": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { "TextEncoder": true @@ -4274,18 +4193,7 @@ }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4609,20 +4517,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index fae253f8b9d5..07796dc92f74 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -182,16 +182,28 @@ "crypto": true }, "packages": { + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": true, - "@metamask/message-signing-snap>@noble/curves": true, - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethereumjs/tx>ethereum-cryptography>@scure/bip32": { "packages": { + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": true, "@metamask/message-signing-snap>@noble/curves": true, - "@metamask/utils>@scure/base": true, - "@noble/hashes": true + "@metamask/utils>@scure/base": true + } + }, + "@ethereumjs/tx>ethereum-cryptography>@scure/bip32>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@ethersproject/abi": { @@ -1590,7 +1602,13 @@ "TextEncoder": true }, "packages": { - "@noble/hashes": true + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": true + } + }, + "@metamask/message-signing-snap>@noble/curves>@noble/hashes": { + "globals": { + "TextEncoder": true, + "crypto": true } }, "@metamask/name-controller": { @@ -4165,59 +4183,16 @@ "setInterval": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/util": true, "bn.js": true, "browserify>buffer": true, "crypto-browserify": true, - "eth-lattice-keyring>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk": true, "eth-lattice-keyring>rlp": true, "webpack>events": true } }, - "eth-lattice-keyring>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common": true, - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": { - "packages": { - "browserify": true, - "browserify>buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>case": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz>@chainsafe/persistent-merkle-tree": { - "globals": { - "WeakRef": true - }, - "packages": { - "browserify": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk": { "globals": { "AbortController": true, @@ -4233,20 +4208,20 @@ "setTimeout": true }, "packages": { + "@ethereumjs/tx": true, "@ethereumjs/tx>@ethereumjs/common>crc-32": true, "@ethersproject/abi": true, + "@metamask/eth-sig-util": true, "@metamask/ethjs>js-sha3": true, "@metamask/keyring-api>bech32": true, + "@metamask/ppom-validator>elliptic": true, "bn.js": true, "browserify>buffer": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>aes-js": true, "eth-lattice-keyring>gridplus-sdk>bignumber.js": true, "eth-lattice-keyring>gridplus-sdk>bitwise": true, "eth-lattice-keyring>gridplus-sdk>borc": true, - "eth-lattice-keyring>gridplus-sdk>elliptic": true, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": true, "eth-lattice-keyring>gridplus-sdk>rlp": true, "eth-lattice-keyring>gridplus-sdk>secp256k1": true, "eth-lattice-keyring>gridplus-sdk>uuid": true, @@ -4263,41 +4238,6 @@ "webpack>events": true } }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": { - "packages": { - "@ethereumjs/tx>@ethereumjs/rlp": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "@ethersproject/providers": true, - "browserify>buffer": true, - "browserify>insert-module-globals>is-buffer": true, - "eth-lattice-keyring>@ethereumjs/tx>@chainsafe/ssz": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": true, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>@ethereumjs/common": { - "packages": { - "@ethereumjs/tx>@ethereumjs/common>crc-32": true, - "@ethereumjs/tx>@ethereumjs/util": true, - "browserify>buffer": true, - "webpack>events": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography": { - "globals": { - "TextDecoder": true, - "crypto": true - }, - "packages": { - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": true - } - }, - "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx>ethereum-cryptography>@noble/hashes": { - "globals": { - "TextEncoder": true, - "crypto": true - } - }, "eth-lattice-keyring>gridplus-sdk>aes-js": { "globals": { "define": true @@ -4338,27 +4278,6 @@ "location": true } }, - "eth-lattice-keyring>gridplus-sdk>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true - } - }, - "eth-lattice-keyring>gridplus-sdk>eth-eip712-util-browser": { - "globals": { - "intToBuffer": true - }, - "packages": { - "@metamask/ethjs>js-sha3": true, - "bn.js": true, - "buffer": true - } - }, "eth-lattice-keyring>gridplus-sdk>rlp": { "globals": { "TextEncoder": true @@ -4366,18 +4285,7 @@ }, "eth-lattice-keyring>gridplus-sdk>secp256k1": { "packages": { - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": true - } - }, - "eth-lattice-keyring>gridplus-sdk>secp256k1>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "@metamask/ppom-validator>elliptic": true } }, "eth-lattice-keyring>gridplus-sdk>uuid": { @@ -4701,20 +4609,9 @@ "ethers>@ethersproject/signing-key": { "packages": { "@ethersproject/bytes": true, + "@metamask/ppom-validator>elliptic": true, "ethers>@ethersproject/logger": true, - "ethers>@ethersproject/properties": true, - "ethers>@ethersproject/signing-key>elliptic": true - } - }, - "ethers>@ethersproject/signing-key>elliptic": { - "packages": { - "@metamask/ppom-validator>elliptic>brorand": true, - "@metamask/ppom-validator>elliptic>hmac-drbg": true, - "@metamask/ppom-validator>elliptic>minimalistic-assert": true, - "@metamask/ppom-validator>elliptic>minimalistic-crypto-utils": true, - "bn.js": true, - "ethers>@ethersproject/sha2>hash.js": true, - "pumpify>inherits": true + "ethers>@ethersproject/properties": true } }, "ethers>@ethersproject/solidity": { diff --git a/package.json b/package.json index c3b60bfa1e48..2b5baa029c23 100644 --- a/package.json +++ b/package.json @@ -132,6 +132,13 @@ }, "resolutions": { "chokidar": "^3.6.0", + "gridplus-sdk": "~2.6.0", + "gridplus-sdk/secp256k1": "^5.0.1", + "eth-lattice-keyring/@ethereumjs/tx": "^4.2.0", + "gridplus-sdk/@ethereumjs/tx": "^4.2.0", + "@ethersproject/signing-key/elliptic": "^6.5.7", + "gridplus-sdk/elliptic": "^6.5.7", + "ganache/secp256k1": "^4.0.4", "simple-update-notifier@^1.0.0": "^2.0.0", "@babel/core": "patch:@babel/core@npm%3A7.23.2#~/.yarn/patches/@babel-core-npm-7.23.2-b93f586907.patch", "@types/react": "^16.9.53", @@ -698,16 +705,9 @@ "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>@ledgerhq/hw-transport-node-hid-noevents>node-hid": false, "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>node-hid": false, "@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>usb": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-util>keccak": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-util>secp256k1": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>keccak": false, - "@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>secp256k1": false, - "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": false, "@storybook/api>core-js": false, "@storybook/core>@storybook/core-client>@storybook/ui>core-js-pure": false, "@storybook/test-runner>@storybook/core-common>esbuild": false, - "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>keccak": false, - "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false, "eth-lattice-keyring>gridplus-sdk": false, "ethereumjs-util>ethereum-cryptography>keccak": false, "ganache>@trufflesuite/bigint-buffer": false, @@ -718,13 +718,10 @@ "ganache>leveldown": false, "ganache>secp256k1": false, "ganache>utf-8-validate": false, - "ethereumjs-util>ethereum-cryptography>secp256k1": false, "gulp-watch>chokidar>fsevents": false, "gulp>glob-watcher>chokidar>fsevents": false, "webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, - "@keystonehq/bc-ur-registry-eth>hdkey>secp256k1": false, "eth-lattice-keyring>gridplus-sdk>secp256k1": false, - "eth-lattice-keyring>secp256k1": false, "@storybook/react>@pmmmwh/react-refresh-webpack-plugin>core-js-pure": false, "@testing-library/jest-dom>aria-query>@babel/runtime-corejs3>core-js-pure": false, "web3": false, @@ -733,7 +730,6 @@ "web3>web3-core>web3-core-requestmanager>web3-providers-ws>websocket>es5-ext": false, "web3>web3-core>web3-core-requestmanager>web3-providers-ws>websocket>utf-8-validate": false, "web3>web3-shh": false, - "@keystonehq/metamask-airgapped-keyring>@keystonehq/base-eth-keyring>hdkey>secp256k1": false, "@metamask/base-controller>simple-git-hooks": false, "@storybook/core>@storybook/core-server>webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false, "resolve-url-loader>es6-iterator>es5-ext": false, diff --git a/yarn.lock b/yarn.lock index af059f8960e9..4c9e13f82134 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1725,33 +1725,6 @@ __metadata: languageName: node linkType: hard -"@chainsafe/as-sha256@npm:^0.3.1": - version: 0.3.1 - resolution: "@chainsafe/as-sha256@npm:0.3.1" - checksum: 10/3bae7b4bc6e307baa3cf1f9d2c75827874cd0fb458bc592656d741d374b48e71c042fe21616a506cb821487a5abfc6b92181e4b7fbf49b7370cee4df0b67d95a - languageName: node - linkType: hard - -"@chainsafe/persistent-merkle-tree@npm:^0.4.2": - version: 0.4.2 - resolution: "@chainsafe/persistent-merkle-tree@npm:0.4.2" - dependencies: - "@chainsafe/as-sha256": "npm:^0.3.1" - checksum: 10/a7e59f80be3ce0a86fe452a3c003bd159a1719ed22cae22e9841668f0eda8c35412fa16b3b150d96f583a24f430a5cc2a1bfcabafc1b9cf6e1fdb227e98c4dc7 - languageName: node - linkType: hard - -"@chainsafe/ssz@npm:0.9.4": - version: 0.9.4 - resolution: "@chainsafe/ssz@npm:0.9.4" - dependencies: - "@chainsafe/as-sha256": "npm:^0.3.1" - "@chainsafe/persistent-merkle-tree": "npm:^0.4.2" - case: "npm:^1.6.3" - checksum: 10/2fe83d0b3ef131e14b51b88bb3343b14e7a02185fa9fd3da84b4726dbd857daaa4f7f6f4840fe3772fc1380352b1675a13b5f6153c4211c0f00ffa542b62bf2f - languageName: node - linkType: hard - "@colors/colors@npm:1.5.0": version: 1.5.0 resolution: "@colors/colors@npm:1.5.0" @@ -2363,17 +2336,17 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/common@npm:3.1.1": - version: 3.1.1 - resolution: "@ethereumjs/common@npm:3.1.1" +"@ethereumjs/common@npm:3.1.2": + version: 3.1.2 + resolution: "@ethereumjs/common@npm:3.1.2" dependencies: - "@ethereumjs/util": "npm:^8.0.5" + "@ethereumjs/util": "npm:^8.0.6" crc-32: "npm:^1.2.0" - checksum: 10/dcc3dd9ec23e8817ec0bf5bb2217619a8db08ea937603258831a906702e79c6f6e93b47d6edde551c7f46ce4a0268febacc23cefcb4ca2865be3b5c0bf5ec670 + checksum: 10/f65fda8bf9b86e6f5a7a2d149ddcb6df521fcad52a64378a1f09392fe766a498e60cd3d708613786ec70db82b6a3aac0f8f68ee3271dd36444b908eff02e1a7b languageName: node linkType: hard -"@ethereumjs/common@npm:^3.1.1, @ethereumjs/common@npm:^3.2.0": +"@ethereumjs/common@npm:^3.2.0": version: 3.2.0 resolution: "@ethereumjs/common@npm:3.2.0" dependencies: @@ -2410,25 +2383,6 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/tx@npm:4.1.1": - version: 4.1.1 - resolution: "@ethereumjs/tx@npm:4.1.1" - dependencies: - "@chainsafe/ssz": "npm:0.9.4" - "@ethereumjs/common": "npm:^3.1.1" - "@ethereumjs/rlp": "npm:^4.0.1" - "@ethereumjs/util": "npm:^8.0.5" - "@ethersproject/providers": "npm:^5.7.2" - ethereum-cryptography: "npm:^1.1.2" - peerDependencies: - c-kzg: ^1.0.8 - peerDependenciesMeta: - c-kzg: - optional: true - checksum: 10/3074e198e0a550dd47dc359d16aa3bb9336fc52b14681fb0b1bcc8d4bdac62cc384962a13347819488da18bedf9578d4d5f2491e3609cb7fa7b2f6cafeb18b23 - languageName: node - linkType: hard - "@ethereumjs/tx@npm:^4.0.2, @ethereumjs/tx@npm:^4.1.1, @ethereumjs/tx@npm:^4.2.0": version: 4.2.0 resolution: "@ethereumjs/tx@npm:4.2.0" @@ -2453,7 +2407,7 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/util@npm:^8.0.0, @ethereumjs/util@npm:^8.0.5, @ethereumjs/util@npm:^8.1.0": +"@ethereumjs/util@npm:^8.0.0, @ethereumjs/util@npm:^8.0.5, @ethereumjs/util@npm:^8.0.6, @ethereumjs/util@npm:^8.1.0": version: 8.1.0 resolution: "@ethereumjs/util@npm:8.1.0" dependencies: @@ -2474,7 +2428,7 @@ __metadata: languageName: node linkType: hard -"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.5.0, @ethersproject/abi@npm:^5.6.4, @ethersproject/abi@npm:^5.7.0": +"@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.6.4, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" dependencies: @@ -5341,7 +5295,7 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-sig-util@npm:^7.0.0, @metamask/eth-sig-util@npm:^7.0.1, @metamask/eth-sig-util@npm:^7.0.3": +"@metamask/eth-sig-util@npm:^7.0.0, @metamask/eth-sig-util@npm:^7.0.1, @metamask/eth-sig-util@npm:^7.0.2, @metamask/eth-sig-util@npm:^7.0.3": version: 7.0.3 resolution: "@metamask/eth-sig-util@npm:7.0.3" dependencies: @@ -6692,13 +6646,6 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.1.2": - version: 1.1.2 - resolution: "@noble/hashes@npm:1.1.2" - checksum: 10/2826c94ea30b8d2447fda549f4ffa97a637a480eeef5c96702a2f932c305038465f7436caf5b2bad41eb43c08c270b921e101488b18165feebe3854091b56d91 - languageName: node - linkType: hard - "@noble/hashes@npm:1.3.2": version: 1.3.2 resolution: "@noble/hashes@npm:1.3.2" @@ -6706,17 +6653,17 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.4.0, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:~1.4.0": +"@noble/hashes@npm:1.4.0, @noble/hashes@npm:~1.4.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" checksum: 10/e156e65794c473794c52fa9d06baf1eb20903d0d96719530f523cc4450f6c721a957c544796e6efd0197b2296e7cd70efeb312f861465e17940a3e3c7e0febc6 languageName: node linkType: hard -"@noble/hashes@npm:~1.1.1": - version: 1.1.3 - resolution: "@noble/hashes@npm:1.1.3" - checksum: 10/42e9883649abd85e6a65cfa528e72b2a81ebb601b44db1d71b6ba927cede0627d7d8c649df159a7f84a949dfe17fe268d4b664c5a36c7e0b2a3d4198bc19f5e4 +"@noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.2.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.3.2, @noble/hashes@npm:^1.3.3, @noble/hashes@npm:^1.4.0": + version: 1.5.0 + resolution: "@noble/hashes@npm:1.5.0" + checksum: 10/da7fc7af52af7afcf59810a7eea6155075464ff462ffda2572dc6d57d53e2669b1ea2ec774e814f6273f1697e567f28d36823776c9bf7068cba2a2855140f26e languageName: node linkType: hard @@ -6727,13 +6674,6 @@ __metadata: languageName: node linkType: hard -"@noble/secp256k1@npm:1.6.3, @noble/secp256k1@npm:~1.6.0": - version: 1.6.3 - resolution: "@noble/secp256k1@npm:1.6.3" - checksum: 10/e4f4b0cfa1c5d23fb1b9938fa3cce1a1160a76a89eb91f6dde98075bbdf328709d51771c85b6b4b118f8ce5a6c6554da6c9af7de7716aba56cef30f61a715bd7 - languageName: node - linkType: hard - "@noble/secp256k1@npm:^1.7.0": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" @@ -7851,21 +7791,10 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.1.0, @scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": - version: 1.1.7 - resolution: "@scure/base@npm:1.1.7" - checksum: 10/fc50ffaab36cb46ff9fa4dc5052a06089ab6a6707f63d596bb34aaaec76173c9a564ac312a0b981b5e7a5349d60097b8878673c75d6cbfc4da7012b63a82099b - languageName: node - linkType: hard - -"@scure/bip32@npm:1.1.0": - version: 1.1.0 - resolution: "@scure/bip32@npm:1.1.0" - dependencies: - "@noble/hashes": "npm:~1.1.1" - "@noble/secp256k1": "npm:~1.6.0" - "@scure/base": "npm:~1.1.0" - checksum: 10/e58660fc96dc5c87d0047bf41150fa3b424617e6289ba522cc81bdeecaf1a26e34f01dcd9d76f3e5c2c570ced608a527733cc375abfce4dc9b8e2365719ea5d3 +"@scure/base@npm:^1.0.0, @scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.1.3, @scure/base@npm:~1.1.6": + version: 1.1.9 + resolution: "@scure/base@npm:1.1.9" + checksum: 10/f0ab7f687bbcdee2a01377fe3cd808bf63977999672751295b6a92625d5322f4754a96d40f6bd579bc367aad48ecf8a4e6d0390e70296e6ded1076f52adb16bb languageName: node linkType: hard @@ -7880,16 +7809,6 @@ __metadata: languageName: node linkType: hard -"@scure/bip39@npm:1.1.0": - version: 1.1.0 - resolution: "@scure/bip39@npm:1.1.0" - dependencies: - "@noble/hashes": "npm:~1.1.1" - "@scure/base": "npm:~1.1.0" - checksum: 10/d843be225dda4b6b2c0f90e52e00eef708df3cecbc944902298d487c669a6d219bd41877b20adaf72ba84aec2f0cb1e4567dafc6ce7295d9f132bdb0dcb375b3 - languageName: node - linkType: hard - "@scure/bip39@npm:1.3.0": version: 1.3.0 resolution: "@scure/bip39@npm:1.3.0" @@ -13511,9 +13430,9 @@ __metadata: linkType: hard "bitwise@npm:^2.0.4": - version: 2.1.0 - resolution: "bitwise@npm:2.1.0" - checksum: 10/d075220e8b8d1e41d0e60c7081811eef108024a094c4e7f5c2ad67235f3bcac9f6ffd218884900591d602fbd61aff9a6c1d650cd5a0e0e34f12e11623aab5da1 + version: 2.2.1 + resolution: "bitwise@npm:2.2.1" + checksum: 10/517aea40f326847935a8ae4367d6beca596982ad55db1d0288a4055c9eba78c6b3ccd10d9ad423df356d946d9a898b36c0d5c06673fba4fb98fb1b58df74788e languageName: node linkType: hard @@ -14416,13 +14335,6 @@ __metadata: languageName: node linkType: hard -"case@npm:^1.6.3": - version: 1.6.3 - resolution: "case@npm:1.6.3" - checksum: 10/2fc1df75bbb4118339e06141b9a54aba95cc62460ac92730290144fbec6b6a04f5bf7abf6a6486a1338f5821bd184402f216cec8cea0472451759c27e20fc332 - languageName: node - linkType: hard - "cashaddrjs@npm:0.4.4": version: 0.4.4 resolution: "cashaddrjs@npm:0.4.4" @@ -15559,14 +15471,11 @@ __metadata: linkType: hard "crc-32@npm:^1.2.0": - version: 1.2.0 - resolution: "crc-32@npm:1.2.0" - dependencies: - exit-on-epipe: "npm:~1.0.1" - printj: "npm:~1.1.0" + version: 1.2.2 + resolution: "crc-32@npm:1.2.2" bin: - crc32: ./bin/crc32.njs - checksum: 10/10c648c986b005ed0ea8393bb0d1ccb99e7a102505b136d313dee6abe204aa682d9bb9bc6fd180f9cd98ef92aa029964f1cc96a2a85eb50507dedd9ead1a262f + crc32: bin/crc32.njs + checksum: 10/824f696a5baaf617809aa9cd033313c8f94f12d15ebffa69f10202480396be44aef9831d900ab291638a8022ed91c360696dd5b1ba691eb3f34e60be8835b7c3 languageName: node linkType: hard @@ -17222,24 +17131,9 @@ __metadata: languageName: node linkType: hard -"elliptic@npm:6.5.4": - version: 6.5.4 - resolution: "elliptic@npm:6.5.4" - dependencies: - bn.js: "npm:^4.11.9" - brorand: "npm:^1.1.0" - hash.js: "npm:^1.0.0" - hmac-drbg: "npm:^1.0.1" - inherits: "npm:^2.0.4" - minimalistic-assert: "npm:^1.0.1" - minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10/2cd7ff4b69720dbb2ca1ca650b2cf889d1df60c96d4a99d331931e4fe21e45a7f3b8074e86618ca7e56366c4b6258007f234f9d61d9b0c87bbbc8ea990b99e94 - languageName: node - linkType: hard - -"elliptic@npm:^6.0.0, elliptic@npm:^6.4.0, elliptic@npm:^6.5.2, elliptic@npm:^6.5.4": - version: 6.5.6 - resolution: "elliptic@npm:6.5.6" +"elliptic@npm:^6.0.0, elliptic@npm:^6.4.0, elliptic@npm:^6.5.4, elliptic@npm:^6.5.7": + version: 6.5.7 + resolution: "elliptic@npm:6.5.7" dependencies: bn.js: "npm:^4.11.9" brorand: "npm:^1.1.0" @@ -17248,7 +17142,7 @@ __metadata: inherits: "npm:^2.0.4" minimalistic-assert: "npm:^1.0.1" minimalistic-crypto-utils: "npm:^1.0.1" - checksum: 10/09377ec924fdb37775d63e5d7e5ebb2845842e6f08880b68265b1108863e968970c4a4e1c43df622078c8262417deec9a04aeb9d34e8d09a9693e19b5454e1df + checksum: 10/fbad1fad0a5cc07df83f80cc1f7a784247ef59075194d3e340eaeb2f4dd594825ee24c7e9b0cf279c9f1982efe610503bb3139737926428c4821d4fca1bcf348 languageName: node linkType: hard @@ -18424,20 +18318,9 @@ __metadata: linkType: hard "eth-chainlist@npm:~0.0.498": - version: 0.0.498 - resolution: "eth-chainlist@npm:0.0.498" - checksum: 10/a414c0e1f0a877f9ab8bf1cf775556308ddbb66618e368666d4dea9a0b949febedf8ca5440cf57419413404e7661f1e3d040802faf532d0e1618c40ecd334cbf - languageName: node - linkType: hard - -"eth-eip712-util-browser@npm:^0.0.3": - version: 0.0.3 - resolution: "eth-eip712-util-browser@npm:0.0.3" - dependencies: - bn.js: "npm:>4.0.0" - buffer: "npm:^6.0.3" - js-sha3: "npm:^0.8.0" - checksum: 10/f953e553da8326cc7eacffd7edc4c5ca4ba66ddf27546412cbed961900d50bbd8196b44665bd9e8f7d63c3b64df0793a6a8a60cc2f15b340763a78e84c4e7bd4 + version: 0.0.519 + resolution: "eth-chainlist@npm:0.0.519" + checksum: 10/c9767c64e58d140d04e6fcca9589c50edab48a5c57a62f2c749279574a9ab3e13784b05ab4c05c7b020fe8421769bc4119bd7a904df040fbb076827aaac3de23 languageName: node linkType: hard @@ -18509,18 +18392,6 @@ __metadata: languageName: node linkType: hard -"ethereum-cryptography@npm:^1.1.2": - version: 1.1.2 - resolution: "ethereum-cryptography@npm:1.1.2" - dependencies: - "@noble/hashes": "npm:1.1.2" - "@noble/secp256k1": "npm:1.6.3" - "@scure/bip32": "npm:1.1.0" - "@scure/bip39": "npm:1.1.0" - checksum: 10/abf9288086002a697e0ee0077d77d001c8e1306fa53ea8d7901f9744786f47d073caa6c266bd5b25a283a5c0fbc8beed9fa9cd90d842dc51339e6748aa1ab46a - languageName: node - linkType: hard - "ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2, ethereum-cryptography@npm:^2.2.1": version: 2.2.1 resolution: "ethereum-cryptography@npm:2.2.1" @@ -18813,13 +18684,6 @@ __metadata: languageName: node linkType: hard -"exit-on-epipe@npm:~1.0.1": - version: 1.0.1 - resolution: "exit-on-epipe@npm:1.0.1" - checksum: 10/b180aa277aec5bef2609b34e5876061f421a1f81bf343beb213c4d60b382ddcb6b83012833f0ba329d6bc38042685c8d89b1c52ea495b9b6327948ea80627398 - languageName: node - linkType: hard - "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -20786,30 +20650,30 @@ __metadata: languageName: node linkType: hard -"gridplus-sdk@npm:^2.5.1": - version: 2.5.1 - resolution: "gridplus-sdk@npm:2.5.1" +"gridplus-sdk@npm:~2.6.0": + version: 2.6.0 + resolution: "gridplus-sdk@npm:2.6.0" dependencies: - "@ethereumjs/common": "npm:3.1.1" - "@ethereumjs/tx": "npm:4.1.1" - "@ethersproject/abi": "npm:^5.5.0" + "@ethereumjs/common": "npm:3.1.2" + "@ethereumjs/tx": "npm:4.1.2" + "@ethersproject/abi": "npm:^5.7.0" + "@metamask/eth-sig-util": "npm:^7.0.2" "@types/uuid": "npm:^9.0.0" aes-js: "npm:^3.1.1" bech32: "npm:^2.0.0" - bignumber.js: "npm:^9.0.1" + bignumber.js: "npm:^9.1.1" bitwise: "npm:^2.0.4" borc: "npm:^2.1.2" bs58check: "npm:^2.1.2" - buffer: "npm:^5.6.0" + buffer: "npm:^6.0.3" crc-32: "npm:^1.2.0" elliptic: "npm:6.5.4" - eth-eip712-util-browser: "npm:^0.0.3" hash.js: "npm:^1.1.7" - js-sha3: "npm:^0.8.0" + js-sha3: "npm:^0.9.3" rlp: "npm:^3.0.0" - secp256k1: "npm:4.0.2" + secp256k1: "npm:5.0.0" uuid: "npm:^9.0.0" - checksum: 10/57deeae78fc5f904309e689054baabaed8b078b896ecfd5d724889c6ea424a113db64c3fd79d4dca7cc5f558167d7af754506df5c0692ee76087822ae60c3873 + checksum: 10/d3b845ea5d69fd9b95698175efe1918fb39294a6e43ffcf1d771a0143ae45fb9a25569d496ab510cfb508c779482153800c2e5c7c9c1c62280ff73cab4a1ac45 languageName: node linkType: hard @@ -27667,6 +27531,15 @@ __metadata: languageName: node linkType: hard +"node-addon-api@npm:^5.0.0": + version: 5.1.0 + resolution: "node-addon-api@npm:5.1.0" + dependencies: + node-gyp: "npm:latest" + checksum: 10/595f59ffb4630564f587c502119cbd980d302e482781021f3b479f5fc7e41cf8f2f7280fdc2795f32d148e4f3259bd15043c52d4a3442796aa6f1ae97b959636 + languageName: node + linkType: hard + "node-addon-api@npm:^7.0.0": version: 7.1.0 resolution: "node-addon-api@npm:7.1.0" @@ -29725,15 +29598,6 @@ __metadata: languageName: node linkType: hard -"printj@npm:~1.1.0": - version: 1.1.2 - resolution: "printj@npm:1.1.2" - bin: - printj: ./bin/printj.njs - checksum: 10/45376a5ee7ef2e0d7ff0b4fecc893d73995a332e63d7e0622a544fe662c8213d22f0c9750e627c6d732a7d7a543266be960e6cd51cf19485cce87cf80468bb41 - languageName: node - linkType: hard - "prismjs@npm:^1.27.0": version: 1.29.0 resolution: "prismjs@npm:1.29.0" @@ -32591,27 +32455,27 @@ __metadata: languageName: node linkType: hard -"secp256k1@npm:4.0.2": - version: 4.0.2 - resolution: "secp256k1@npm:4.0.2" +"secp256k1@npm:^4.0.0, secp256k1@npm:^4.0.1, secp256k1@npm:^4.0.4": + version: 4.0.4 + resolution: "secp256k1@npm:4.0.4" dependencies: - elliptic: "npm:^6.5.2" - node-addon-api: "npm:^2.0.0" + elliptic: "npm:^6.5.7" + node-addon-api: "npm:^5.0.0" node-gyp: "npm:latest" node-gyp-build: "npm:^4.2.0" - checksum: 10/80f0a5b44dbe0a062ed0fbf2a82044037a2598a0ea6ec5a0924bfa1f53006b423a43db82ff1cb2924d280b06f2a34235a1733631b3459b86b7a886c0ef41e0c5 + checksum: 10/45000f348c853df7c1e2b67c48efb062ae78c0620ab1a5cfb02fa20d3aad39c641f4e7a18b3de3b54a7c0cc1e0addeb8ecd9d88bc332e92df17a92b60c36122a languageName: node linkType: hard -"secp256k1@npm:4.0.3, secp256k1@npm:^4.0.0, secp256k1@npm:^4.0.1": - version: 4.0.3 - resolution: "secp256k1@npm:4.0.3" +"secp256k1@npm:^5.0.1": + version: 5.0.1 + resolution: "secp256k1@npm:5.0.1" dependencies: - elliptic: "npm:^6.5.4" - node-addon-api: "npm:^2.0.0" + elliptic: "npm:^6.5.7" + node-addon-api: "npm:^5.0.0" node-gyp: "npm:latest" node-gyp-build: "npm:^4.2.0" - checksum: 10/8b45820cd90fd2f95cc8fdb9bf8a71e572de09f2311911ae461a951ffa9e30c99186a129d0f1afeb380dd67eca0c10493f8a7513c39063fda015e99995088e3b + checksum: 10/63fbd35624be4fd9cf3d39e5f79c5471b4a8aea6944453b2bea7b100bb1c77a25c55e6e08e2210cdabdf478c4c62d34c408b34214f2afd9367e19a52a3a4236c languageName: node linkType: hard From d8f786bf6b4c2c1c315ad1050dca2cf0e3c85c73 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Tue, 22 Oct 2024 15:08:26 +0200 Subject: [PATCH 28/46] fix(snaps): Adjust alignment of custom UI links (#27957) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR fixes the alignment issues of the custom UI link. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27957?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** ```ts import { Address, Box, Button, Container, Footer, Link, Row, Text, type SnapComponent, } from '@metamask/snaps-sdk/jsx'; /** * A custom dialog component. * * @returns The custom dialog component. */ export const CustomDialog: SnapComponent = () => (
This is a link This is a long text that should wrap around and take up multiple lines to test the layout of the dialog with a{' '} very very very very long link that should wrap on multiple lines, we will see {' '} in the middle.
); ``` ## **Screenshots/Recordings** ### **Before** ![Screenshot from 2024-10-21 12-34-40](https://github.com/user-attachments/assets/3838dafa-8143-4b3d-bb28-699ce139e7da) ### **After** ![Screenshot from 2024-10-21 15-06-57](https://github.com/user-attachments/assets/f789dc89-3550-416f-8ada-dcb86f01c151) ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.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-extension/blob/develop/.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. --- ui/components/app/app-components.scss | 1 + .../snap-ui-address.test.tsx.snap | 26 +++++++++---------- .../snaps/snap-ui-address/snap-ui-address.tsx | 7 ++++- .../app/snaps/snap-ui-link/index.scss | 11 ++++++++ .../app/snaps/snap-ui-link/snap-ui-link.js | 11 ++++++-- .../app/snaps/snap-ui-renderer/index.scss | 8 +++--- 6 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 ui/components/app/snaps/snap-ui-link/index.scss diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index 0995f4b52a4a..9eefd48028ac 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -25,6 +25,7 @@ @import 'snaps/snap-ui-input/index'; @import 'snaps/snap-ui-file-input/index'; @import 'snaps/snap-ui-selector/index'; +@import 'snaps/snap-ui-link/index'; @import 'snaps/snap-delineator/index'; @import 'snaps/snap-home-menu/index'; @import 'snaps/snap-list-item/index'; diff --git a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap index d29236409dbc..7dd3749a6e5f 100644 --- a/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap +++ b/ui/components/app/snaps/snap-ui-address/__snapshots__/snap-ui-address.test.tsx.snap @@ -3,7 +3,7 @@ exports[`SnapUIAddress renders Bitcoin address 1`] = `
= ({ const shortenedAddress = shortenAddress(transformedAddress); return ( - + {shortenedAddress} diff --git a/ui/components/app/snaps/snap-ui-link/index.scss b/ui/components/app/snaps/snap-ui-link/index.scss new file mode 100644 index 000000000000..7d3f75f0e372 --- /dev/null +++ b/ui/components/app/snaps/snap-ui-link/index.scss @@ -0,0 +1,11 @@ +.snap-ui-renderer__link { + & .snap-ui-renderer__address { + // Fixes an issue where the link end icon would wrap + display: inline-flex; + } + + .snap-ui-renderer__address + .mm-icon { + // This fixes an issue where the icon would be misaligned with the Address component + top: 0; + } +} diff --git a/ui/components/app/snaps/snap-ui-link/snap-ui-link.js b/ui/components/app/snaps/snap-ui-link/snap-ui-link.js index a1289543fd45..58a22008a52a 100644 --- a/ui/components/app/snaps/snap-ui-link/snap-ui-link.js +++ b/ui/components/app/snaps/snap-ui-link/snap-ui-link.js @@ -34,7 +34,7 @@ export const SnapUILink = ({ href, children }) => { {children} @@ -51,7 +51,14 @@ export const SnapUILink = ({ href, children }) => { externalLink size={ButtonLinkSize.Inherit} display={Display.Inline} - className="snap-ui-link" + className="snap-ui-renderer__link" + style={{ + // Prevents the link from taking up the full width of the parent. + width: 'fit-content', + }} + textProps={{ + display: Display.Inline, + }} > {children} diff --git a/ui/components/app/snaps/snap-ui-renderer/index.scss b/ui/components/app/snaps/snap-ui-renderer/index.scss index 7e18e72c917f..d32edf726479 100644 --- a/ui/components/app/snaps/snap-ui-renderer/index.scss +++ b/ui/components/app/snaps/snap-ui-renderer/index.scss @@ -34,6 +34,10 @@ border-radius: 8px; border-color: var(--color-border-muted); + & .mm-icon { + top: 0; + } + .mm-text--overflow-wrap-anywhere { overflow-wrap: normal; } @@ -48,10 +52,6 @@ &__panel { gap: 8px; - - .mm-icon--size-inherit { - top: 0; - } } &__text { From c926f9641d8f1e1b8c9ddc3886808ae1891b7608 Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Tue, 22 Oct 2024 18:42:12 +0530 Subject: [PATCH 29/46] fix: updated event name for site cell component (#27981) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is to update the event name for metametrics in site cell component ## **Related issues** Fixes: [https://github.com/MetaMask/MetaMask-planning/issues/3263](https://github.com/MetaMask/MetaMask-planning/issues/3263) ## **Manual testing steps** 1. Go to ui/contexts/metametrics.js 2. In trackEvent in this file, add a log to see the payload 3. Run extension with yarn start. Go to Permissions Page, click on edit button for accounts and networks and check the console to verify the payload. ## **Screenshots/Recordings** ### **Before** NA ### **After** NA ## **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/develop/.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/develop/.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. --- .../pages/review-permissions-page/site-cell/site-cell.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/components/multichain/pages/review-permissions-page/site-cell/site-cell.tsx b/ui/components/multichain/pages/review-permissions-page/site-cell/site-cell.tsx index ae7a93283ead..9f77238bda9a 100644 --- a/ui/components/multichain/pages/review-permissions-page/site-cell/site-cell.tsx +++ b/ui/components/multichain/pages/review-permissions-page/site-cell/site-cell.tsx @@ -100,7 +100,7 @@ export const SiteCell: React.FC = ({ setShowEditAccountsModal(true); trackEvent({ category: MetaMetricsEventCategory.Navigation, - event: MetaMetricsEventName.TokenImportButtonClicked, + event: MetaMetricsEventName.ViewPermissionedAccounts, properties: { location: 'Connect view, Permissions toast, Permissions (dapp)', }, @@ -133,7 +133,7 @@ export const SiteCell: React.FC = ({ setShowEditNetworksModal(true); trackEvent({ category: MetaMetricsEventCategory.Navigation, - event: MetaMetricsEventName.TokenImportButtonClicked, + event: MetaMetricsEventName.ViewPermissionedNetworks, properties: { location: 'Connect view, Permissions toast, Permissions (dapp)', }, From 528f2f50e974c17b21a257a0d05956b4c5d1b644 Mon Sep 17 00:00:00 2001 From: Prithpal Sooriya Date: Tue, 22 Oct 2024 14:40:08 +0100 Subject: [PATCH 30/46] test: update notification date tests to be timezone agnostic (#27925) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** A rare edge-case where unit tests locally (when in a different timezone) failed. This updates the tests to use UTC dates and uses the UTC timezone. NOTE - that these tests pass in CI and need to be tested locally by devs in different timezones. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/27925?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** N/A - this has no impact on the extension, just tests. You can try running this unit test locally to see if it passes. ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **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/develop/.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/develop/.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. --- test/env.js | 1 + ui/helpers/utils/notification.utils.test.ts | 22 ++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/test/env.js b/test/env.js index 2dacb1d888ba..268f01af0e3b 100644 --- a/test/env.js +++ b/test/env.js @@ -16,3 +16,4 @@ process.env.PUSH_NOTIFICATIONS_SERVICE_URL = process.env.PORTFOLIO_URL = 'https://portfolio.test'; process.env.METAMASK_VERSION = 'MOCK_VERSION'; process.env.ENABLE_CONFIRMATION_REDESIGN = 'true'; +process.env.TZ = 'UTC'; diff --git a/ui/helpers/utils/notification.utils.test.ts b/ui/helpers/utils/notification.utils.test.ts index f82f8532cb58..2f4e66c26504 100644 --- a/ui/helpers/utils/notification.utils.test.ts +++ b/ui/helpers/utils/notification.utils.test.ts @@ -9,7 +9,7 @@ import { describe('formatMenuItemDate', () => { beforeAll(() => { jest.useFakeTimers(); - jest.setSystemTime(new Date('2024-06-07T09:40:00Z')); + jest.setSystemTime(new Date(Date.UTC(2024, 5, 7, 9, 40, 0))); // 2024-06-07T09:40:00Z }); afterAll(() => { @@ -28,7 +28,7 @@ describe('formatMenuItemDate', () => { // assert 1 hour ago assertToday((testDate) => { - testDate.setHours(testDate.getHours() - 1); + testDate.setUTCHours(testDate.getUTCHours() - 1); return testDate; }); }); @@ -42,14 +42,14 @@ describe('formatMenuItemDate', () => { // assert exactly 1 day ago assertYesterday((testDate) => { - testDate.setDate(testDate.getDate() - 1); + testDate.setUTCDate(testDate.getUTCDate() - 1); }); // assert almost a day ago, but was still yesterday // E.g. if Today way 09:40AM, but date to test was 23 hours ago (yesterday at 10:40AM), we still want to to show yesterday assertYesterday((testDate) => { - testDate.setDate(testDate.getDate() - 1); - testDate.setHours(testDate.getHours() + 1); + testDate.setUTCDate(testDate.getUTCDate() - 1); + testDate.setUTCHours(testDate.getUTCHours() + 1); }); }); @@ -62,18 +62,18 @@ describe('formatMenuItemDate', () => { // assert exactly 1 month ago assertMonthsAgo((testDate) => { - testDate.setMonth(testDate.getMonth() - 1); + testDate.setUTCMonth(testDate.getUTCMonth() - 1); }); // assert 2 months ago assertMonthsAgo((testDate) => { - testDate.setMonth(testDate.getMonth() - 2); + testDate.setUTCMonth(testDate.getUTCMonth() - 2); }); // assert almost a month ago (where it is a new month, but not 30 days) assertMonthsAgo(() => { // jest mock date is set in july, so we will test with month may - return new Date('2024-05-20T09:40:00Z'); + return new Date(Date.UTC(2024, 4, 20, 9, 40, 0)); // 2024-05-20T09:40:00Z }); }); @@ -86,18 +86,18 @@ describe('formatMenuItemDate', () => { // assert exactly 1 year ago assertYearsAgo((testDate) => { - testDate.setFullYear(testDate.getFullYear() - 1); + testDate.setUTCFullYear(testDate.getUTCFullYear() - 1); }); // assert 2 years ago assertYearsAgo((testDate) => { - testDate.setFullYear(testDate.getFullYear() - 2); + testDate.setUTCFullYear(testDate.getUTCFullYear() - 2); }); // assert almost a year ago (where it is a new year, but not 365 days ago) assertYearsAgo(() => { // jest mock date is set in 2024, so we will test with year 2023 - return new Date('2023-11-20T09:40:00Z'); + return new Date(Date.UTC(2023, 10, 20, 9, 40, 0)); // 2023-11-20T09:40:00Z }); }); }); From 088983ae8d1b1dec408a9ebffecafabff667b03c Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Tue, 22 Oct 2024 19:12:03 +0530 Subject: [PATCH 31/46] feat: removed feature flag for confirmations screen (#27877) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR is to remove the feature flag from confirmations page ## **Related issues** Fixes: [https://github.com/MetaMask/MetaMask-planning/issues/3517](https://github.com/MetaMask/MetaMask-planning/issues/3517) ## **Manual testing steps** 1. Connect extension to a Dapp 2. Try to switch to a non enabled network from Dapp 3. In the confirmations screen, we should not see the network picker 4. The Definition list component should expand and popup should not show up on click of See Details ## **Screenshots/Recordings** ### **Before** ![Screenshot 2024-10-16 at 5 55 15 PM](https://github.com/user-attachments/assets/74984e47-2d42-4c10-9fa9-47193139edad) ### **After** ![Screenshot 2024-10-16 at 5 54 55 PM](https://github.com/user-attachments/assets/ee40e7fc-8980-4d17-9e0e-993cacb6d69c) ## **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/develop/.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/develop/.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. --- app/_locales/de/messages.json | 23 -- app/_locales/el/messages.json | 23 -- app/_locales/en/messages.json | 33 +-- app/_locales/es/messages.json | 23 -- app/_locales/es_419/messages.json | 20 -- app/_locales/fr/messages.json | 23 -- app/_locales/hi/messages.json | 23 -- app/_locales/id/messages.json | 23 -- app/_locales/it/messages.json | 20 -- app/_locales/ja/messages.json | 23 -- app/_locales/ko/messages.json | 23 -- app/_locales/ph/messages.json | 20 -- app/_locales/pt/messages.json | 23 -- app/_locales/pt_BR/messages.json | 20 -- app/_locales/ru/messages.json | 23 -- app/_locales/tl/messages.json | 23 -- app/_locales/tr/messages.json | 23 -- app/_locales/vi/messages.json | 23 -- app/_locales/zh_CN/messages.json | 23 -- app/_locales/zh_TW/messages.json | 20 -- .../dapp-interactions.spec.js | 2 +- .../tests/network/add-custom-network.spec.js | 39 +-- ...om-blockaid-alert-networks-support.spec.js | 2 +- .../ui/definition-list/definition-list.js | 6 +- .../truncated-definition-list.js | 47 +--- .../confirmation/confirmation.js | 9 +- .../confirmation/confirmation.scss | 2 +- .../add-ethereum-chain.test.js.snap | 134 ++------- .../create-named-snap-account.test.js.snap | 2 +- .../create-snap-account.test.js.snap | 2 +- .../__snapshots__/error.test.js.snap | 2 +- .../remove-snap-account.test.js.snap | 2 +- .../snap-account-redirect.test.js.snap | 2 +- .../__snapshots__/success.test.js.snap | 2 +- .../switch-ethereum-chain.test.js.snap | 50 +--- .../templates/add-ethereum-chain.js | 258 +++--------------- .../templates/add-ethereum-chain.test.js | 9 +- 37 files changed, 108 insertions(+), 917 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index fe0c84afcfac..8d1ed215aa92 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Benutzerdefiniertes Netzwerk hinzufügen" }, - "addEthereumChainConfirmationDescription": { - "message": "Dadurch kann dieses Netzwerk innerhalb MetaMask verwendet werden." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask überprüft keine benutzerdefinierten Netzwerke." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Erfahren Sie mehr über $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "Betrug und Sicherheitsrisiken im Netzwerk", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Dieser Seite das Hinzufügen eines Netzwerks erlauben?" - }, "addEthereumChainWarningModalHeader": { "message": "Fügen Sie diesen RPC-Anbieter nur hinzu, wenn Sie sich sicher sind, dass Sie ihm vertrauen können. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Kontaktieren Sie die Ersteller von $1 für weitere Unterstützung.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Einige Netzwerke können Sicherheits- und/oder Datenschutzrisiken bergen. Informieren Sie sich über die Risiken, bevor Sie ein Netzwerk hinzufügen und nutzen." - }, "somethingDoesntLookRight": { "message": "Scheint irgendetwas nicht in Ordnung zu sein? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Aktivität anzeigen" }, - "viewAllDetails": { - "message": "Alle Details anzeigen" - }, "viewAllQuotes": { "message": "alle Angebote anzeigen" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 5c42a8d829b4..7ccc23b123bb 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Προσθήκη προσαρμοσμένου δικτύου" }, - "addEthereumChainConfirmationDescription": { - "message": "Αυτό θα επιτρέψει σε αυτό το δίκτυο να χρησιμοποιηθεί στο MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "Το MetaMask δεν επαληθεύει τα προσαρμοσμένα δίκτυα." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Μάθετε για το $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "απάτες και κίνδυνοι ασφάλειας δικτύου", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Επιτρέπετε σε αυτήν την ιστοσελίδα να προσθέσει ένα δίκτυο;" - }, "addEthereumChainWarningModalHeader": { "message": "Προσθέστε αυτόν τον πάροχο RPC μόνο αν είστε σίγουροι ότι μπορείτε να τον εμπιστευτείτε. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Επικοινωνήστε με τους διαχειριστές του $1 για περαιτέρω υποστήριξη.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Ορισμένα δίκτυα ενδέχεται να ενέχουν κινδύνους για την ασφάλεια ή/και το απόρρητο. Ενημερωθείτε για τους κινδύνους πριν προσθέσετε και χρησιμοποιήσετε ένα δίκτυο." - }, "somethingDoesntLookRight": { "message": "Κάτι δεν φαίνεται σωστό; $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Προβολή δραστηριότητας" }, - "viewAllDetails": { - "message": "Προβολή όλων των λεπτομερειών" - }, "viewAllQuotes": { "message": "προβολή όλων των προσφορών" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 70cb4da8cfb6..b36f3ffcdb4e 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -231,23 +231,6 @@ "addCustomNetwork": { "message": "Add custom network" }, - "addEthereumChainConfirmationDescription": { - "message": "This will allow this network to be used within MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask does not verify custom networks." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Learn about $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "scams and network security risks", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Allow this site to add a network?" - }, "addEthereumChainWarningModalHeader": { "message": "Only add this RPC provider if you’re sure you can trust it. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4668,6 +4651,9 @@ "securityDescription": { "message": "Reduce your chances of joining unsafe networks and protect your accounts" }, + "securityMessageLinkForNetworks": { + "message": "network scams and security risks" + }, "securityPrivacyPath": { "message": "Settings > Security & Privacy." }, @@ -5238,9 +5224,6 @@ "message": "Contact the creators of $1 for further support.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Some networks may pose security and/or privacy risks. Understand the risks before adding & using a network." - }, "somethingDoesntLookRight": { "message": "Something doesn't look right? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6324,9 +6307,6 @@ "unknown": { "message": "Unknown" }, - "unknownChainWarning": { - "message": "We can’t verify custom networks. To avoid malicious providers from recording your network activity, only add networks you trust." - }, "unknownCollection": { "message": "Unnamed collection" }, @@ -6455,9 +6435,6 @@ "viewActivity": { "message": "View activity" }, - "viewAllDetails": { - "message": "View all details" - }, "viewAllQuotes": { "message": "view all quotes" }, @@ -6540,6 +6517,10 @@ "watchEthereumAccountsToggle": { "message": "Watch Ethereum Accounts (Beta)" }, + "watchOutMessage": { + "message": "Beware of $1.", + "description": "$1 is a link with text that is provided by the 'securityMessageLinkForNetworks' key" + }, "weak": { "message": "Weak" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 97d6f4be9854..a2578d1f4137 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Agregar red personalizada" }, - "addEthereumChainConfirmationDescription": { - "message": "Esto permitirá que la red se utilice en MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask no verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Obtenga más información sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "estafas y riesgos de seguridad de la red", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "¿Permitir que este sitio agregue una red?" - }, "addEthereumChainWarningModalHeader": { "message": "Agregue este proveedor de RPC solo si está seguro de que puede confiar en él. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4855,9 +4838,6 @@ "message": "Póngase en contacto con los creadores de $1 para obtener más ayuda.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Algunas redes pueden presentar riesgos de seguridad y/o privacidad. Comprenda los riesgos antes de agregar y utilizar una red." - }, "somethingDoesntLookRight": { "message": "Algo no se ve bien, ¿cierto? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6004,9 +5984,6 @@ "viewActivity": { "message": "Ver actividad" }, - "viewAllDetails": { - "message": "Ver todos los detalles" - }, "viewAllQuotes": { "message": "ver todas las cotizaciones" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 672823c370ba..cebfc3cef106 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -100,23 +100,6 @@ "addContact": { "message": "Agregar contacto" }, - "addEthereumChainConfirmationDescription": { - "message": "Esto permitirá que la red se utilice en MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask no verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Obtenga más información sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "estafas y riesgos de seguridad de la red", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "¿Permitir que este sitio agregue una red?" - }, "addFriendsAndAddresses": { "message": "Agregue amigos y direcciones de confianza" }, @@ -2335,9 +2318,6 @@ "userName": { "message": "Nombre de usuario" }, - "viewAllDetails": { - "message": "Ver todos los detalles" - }, "viewContact": { "message": "Ver contacto" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index dbaffd44cf38..c3151d3ca53f 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Ajouter un réseau personnalisé" }, - "addEthereumChainConfirmationDescription": { - "message": "Cela permettra d’utiliser ce réseau dans MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask ne vérifie pas les réseaux personnalisés." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "En savoir plus sur $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "les risques de fraude et de sécurité des réseaux", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Autoriser ce site à ajouter un réseau ?" - }, "addEthereumChainWarningModalHeader": { "message": "N’ajoutez ce fournisseur de RPC que si vous lui faites confiance. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "L’interface utilisateur (IU) spécifiée par le snap n’est pas valide.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Certains réseaux peuvent présenter des risques pour la sécurité et/ou la vie privée. Informez-vous sur les risques avant d’ajouter et d’utiliser un réseau." - }, "somethingDoesntLookRight": { "message": "On dirait que quelque chose ne va pas ? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Voir l’activité" }, - "viewAllDetails": { - "message": "Afficher tous les détails" - }, "viewAllQuotes": { "message": "afficher toutes les cotations" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 0e624b4ba807..c69c7117d4d0 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "कस्टम नेटवर्क जोड़ें" }, - "addEthereumChainConfirmationDescription": { - "message": "इससे इस नेटवर्क को MetaMask के अंदर इस्तेमाल करने की अनुमति मिलेगी।" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask कस्टम नेटवर्क को वेरीफ़ाई नहीं करता है।" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1 के बारे में जानें।", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "स्कैम और नेटवर्क से जुड़े सुरक्षा जोखिम", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "इस साइट को नेटवर्क जोड़ने की अनुमति दें?" - }, "addEthereumChainWarningModalHeader": { "message": "इस RPC प्रोवाइडर को केवल तभी जोड़ें जब आप निश्चित हैं कि आप इस पर विश्वास कर सकते हैं। $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "अधिक सहायता के लिए $1 के निर्माताओं से कॉन्टेक्ट करें।", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "कुछ नेटवर्क सुरक्षा और/या गोपनीयता संबंधी जोखिम पैदा कर सकते हैं। नेटवर्क जोड़ने और इस्तेमाल करने से पहले जोखिमों को समझें।" - }, "somethingDoesntLookRight": { "message": "कुछ तो गड़बड़ है? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "एक्टिविटी देखें" }, - "viewAllDetails": { - "message": "सभी विवरण देखें" - }, "viewAllQuotes": { "message": "सभी उद्धरण को देखें" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 68b52556c3f6..53e7fd923fda 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Tambahkan jaringan khusus" }, - "addEthereumChainConfirmationDescription": { - "message": "Tindakan ini akan membantu jaringan ini agar dapat digunakan di MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask tidak memverifikasi jaringan kustom." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Pelajari tentang $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "penipuan dan risiko keamanan jaringan", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Izinkan situs ini untuk menambahkan jaringan?" - }, "addEthereumChainWarningModalHeader": { "message": "Cukup tambahkan penyedia RPC ini jika Anda yakin dapat memercayainya. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Hubungi pembuat $1 untuk dukungan lebih lanjut.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Beberapa jaringan dapat menimbulkan risiko keamanan dan/atau privasi. Pahami risikonya sebelum menambahkan dan menggunakan jaringan." - }, "somethingDoesntLookRight": { "message": "Ada yang tidak beres? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Lihat aktivitas" }, - "viewAllDetails": { - "message": "Lihat semua detail" - }, "viewAllQuotes": { "message": "lihat semua kuotasi" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 4dac80c253b3..0c79dd8fc6fc 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -152,23 +152,6 @@ "addContact": { "message": "Aggiungi contatto" }, - "addEthereumChainConfirmationDescription": { - "message": "Ciò consentirà a questa rete di essere utilizzata all'interno di MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask non verifica le reti personalizzate." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Maggiori informazioni su $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "truffe e rischi per la sicurezza della rete", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Consenti a questo sito di aggiungere una rete?" - }, "addFriendsAndAddresses": { "message": "Aggiungi amici e indirizzi di cui ti fidi" }, @@ -1649,9 +1632,6 @@ "userName": { "message": "Nome utente" }, - "viewAllDetails": { - "message": "Vedi tutti i dettagli" - }, "viewContact": { "message": "Visualizza contatto" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 73f3f8300646..c26ec67990b2 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "カスタムネットワークを追加" }, - "addEthereumChainConfirmationDescription": { - "message": "これにより、このネットワークはMetaMask内で使用できるようになります。" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMaskはカスタムネットワークを検証しません。" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1の詳細。", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "詐欺やネットワークセキュリティのリスク", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "このサイトにネットワークの追加を許可しますか?" - }, "addEthereumChainWarningModalHeader": { "message": "このRPCプロバイダーは、確実に信頼できる場合のみ追加してください。$1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "今後のサポートは、$1の作成者にお問い合わせください。", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "ネットワークによっては、セキュリティやプライバシーの面でリスクが伴う可能性があります。ネットワークを追加・使用する前にリスクを理解するようにしてください。" - }, "somethingDoesntLookRight": { "message": "何か不審な点があれば、$1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "アクティビティを表示" }, - "viewAllDetails": { - "message": "すべての詳細の表示" - }, "viewAllQuotes": { "message": "すべてのクォートを表示" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index be1de55c51c7..ad4959a459b9 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "맞춤 네트워크 추가" }, - "addEthereumChainConfirmationDescription": { - "message": "이렇게 하면 MetaMask 내에서 이 네트워크를 사용할 수 있습니다." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask는 맞춤 네트워크를 검증하지 않습니다." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1에 대해 알아보기", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "사기 및 네트워크 보안 위험", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "이 사이트에서 네트워크를 추가하도록 허용하시겠습니까?" - }, "addEthereumChainWarningModalHeader": { "message": "신뢰할 수 있는 경우에만 이 RPC 공급입체를 추가하세요. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "$1 작성자에게 연락하여 향후 지원을 요청하세요.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "네트워크에 따라 보안이나 개인 정보 유출의 위험이 있을 수 있습니다. 네트워크 추가 및 사용 이전에 위험 요소를 파악하세요." - }, "somethingDoesntLookRight": { "message": "무언가 잘못되었나요? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "활동 보기" }, - "viewAllDetails": { - "message": "모든 세부 정보 보기" - }, "viewAllQuotes": { "message": "모든 견적 보기" }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 1687cb7818f0..e6b4bc3e7811 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -42,23 +42,6 @@ "addContact": { "message": "Magdagdag ng contact" }, - "addEthereumChainConfirmationDescription": { - "message": "Bibigyang-daan nito na magamit ang network na ito sa MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "Hindi vine-verify ng MetaMask ang mga custom na network." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Matuto tungkol sa $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "mga scam at panganib sa seguridad ng network", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Payagan ang site na ito na magdagdag ng network?" - }, "addFriendsAndAddresses": { "message": "Magdagdag ng mga kaibigan at address na pinagkakatiwalaan mo" }, @@ -1594,9 +1577,6 @@ "userName": { "message": "Username" }, - "viewAllDetails": { - "message": "Tingnan ang lahat ng detalye" - }, "viewContact": { "message": "Tingnan ang Contact" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 656733cecf65..7831e080500b 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Adicionar rede personalizada" }, - "addEthereumChainConfirmationDescription": { - "message": "Isso permitirá que essa rede seja usada dentro da MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "A MetaMask não verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Saiba mais sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "golpes e riscos de segurança nas redes", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Permitir que este site adicione uma rede?" - }, "addEthereumChainWarningModalHeader": { "message": "Adicione esse provedor de RPC apenas se tiver certeza de que é confiável. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Contate os criadores de $1 para receber mais suporte.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Algumas redes podem representar riscos de segurança e/ou privacidade. Tenha os riscos em mente antes de adicionar e usar uma rede." - }, "somethingDoesntLookRight": { "message": "Alguma coisa não parece certa? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Ver atividade" }, - "viewAllDetails": { - "message": "Ver todos os detalhes" - }, "viewAllQuotes": { "message": "ver todas as cotações" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 6062013d6d6f..58d7f6ea8718 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -100,23 +100,6 @@ "addContact": { "message": "Adicionar contato" }, - "addEthereumChainConfirmationDescription": { - "message": "Isso permitirá que essa rede seja usada dentro da MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "A MetaMask não verifica redes personalizadas." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Saiba mais sobre $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "fraudes e riscos de segurança da rede", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Permitir que esse site adicione uma rede?" - }, "addFriendsAndAddresses": { "message": "Adicionar amigos e endereços confiáveis" }, @@ -2335,9 +2318,6 @@ "userName": { "message": "Nome de usuário" }, - "viewAllDetails": { - "message": "Ver todos os detalhes" - }, "viewContact": { "message": "Ver contato" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 0c2f92821ed2..d32a603b367b 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Добавить пользовательскую сеть" }, - "addEthereumChainConfirmationDescription": { - "message": "Это позволит использовать эту сеть в MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask не проверяет пользовательские сети." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Подробнее о $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "мошенничестве и угрозах безопасности в сети", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Разрешить этому сайту добавить сеть?" - }, "addEthereumChainWarningModalHeader": { "message": "Добавляйте этого поставщика RPC только в том случае, если уверены, что ему можно доверять. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Свяжитесь с авторами $1 для получения дополнительной поддержки.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Некоторые сети могут представлять угрозу безопасности и/или конфиденциальности. Прежде чем добавлять и использовать сеть, ознакомьтесь с рисками." - }, "somethingDoesntLookRight": { "message": "Что-то не так? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Смотреть активность" }, - "viewAllDetails": { - "message": "Смотреть все сведения" - }, "viewAllQuotes": { "message": "смотреть все котировки" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 61d8ff6e5d8c..0c3675d78754 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Magdagdag ng custom na network" }, - "addEthereumChainConfirmationDescription": { - "message": "Magpapahintulot ito sa network na ito na gamitin sa loob ng MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "Ang MetaMask ay hindi nagve-verify ng mga custom na network." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Alamin ang tungkol sa $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "mga panloloko at panganib ng seguridad ng network", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Payagan ang site na ito na magdagdag ng network?" - }, "addEthereumChainWarningModalHeader": { "message": "Idagdag lamang ang RPC provider na ito kung sigurado kang mapagkakatiwalaan ito. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Makipag-ugnayan sa mga tagalikha ng $1 para sa karagdagang suporta.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Maaaring magdulot ang ilang network ng mga panganib sa seguridad at/o pagkapribado. Unawain ang mga panganib bago idagdag o gamitin ang isang network." - }, "somethingDoesntLookRight": { "message": "Mayroon bang hindi tama? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Tingnan ang aktibidad" }, - "viewAllDetails": { - "message": "Tingnan ang lahat ng detalye" - }, "viewAllQuotes": { "message": "tingnan ang lahat ng quote" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index d80d6564b880..253e00845388 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Özel ağ ekle" }, - "addEthereumChainConfirmationDescription": { - "message": "Bu, bu ağın MetaMas dahilinde kullanılmasına olanak tanıyacaktır." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask özel ağları doğrulamaz." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "$1 hakkında bilgi edinin.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "dolandırıcılık ve ağ güvenliği riskleri", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Bu sitenin ağ eklemesine izin ver?" - }, "addEthereumChainWarningModalHeader": { "message": "Bu RPC sağlayıcısını sadece ona güvenebileceğinizden eminseniz ekleyin. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Daha fazla destek için $1 oluşturucuları ile iletişime geçin.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Bazı ağlar güvenlik ve/veya gizlilik riskleri teşkil edebilir. Bir ağ eklemeden ve kullanmadan önce riskleri anlayın." - }, "somethingDoesntLookRight": { "message": "Doğru görünmeyen bir şeyler mi var? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Aktiviteyi görüntüle" }, - "viewAllDetails": { - "message": "Tüm bilgileri görüntüle" - }, "viewAllQuotes": { "message": "tüm teklifleri görüntüle" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 0bac5423d1ee..538108c0677d 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "Thêm mạng tùy chỉnh" }, - "addEthereumChainConfirmationDescription": { - "message": "Thao tác này sẽ cho phép sử dụng mạng này trong MetaMask." - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask không xác minh mạng tùy chỉnh." - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "Tìm hiểu về $1.", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "lừa đảo và các nguy cơ về an ninh mạng", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "Cho phép trang này thêm một mạng?" - }, "addEthereumChainWarningModalHeader": { "message": "Chỉ thêm nhà cung cấp RPC này nếu bạn chắc chắn bạn có thể tin tưởng. $1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "Liên hệ với những người tạo ra $1 để được hỗ trợ thêm.", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "Một số mạng có thể gây ra rủi ro về bảo mật và/hoặc quyền riêng tư. Bạn cần hiểu rõ các rủi ro này trước khi thêm và sử dụng mạng." - }, "somethingDoesntLookRight": { "message": "Có gì đó không ổn? $1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "Xem hoạt động" }, - "viewAllDetails": { - "message": "Xem toàn bộ chi tiết" - }, "viewAllQuotes": { "message": "xem tất cả báo giá" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 7209fb1c5b44..d3a4af11220a 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -207,23 +207,6 @@ "addCustomNetwork": { "message": "添加自定义网络" }, - "addEthereumChainConfirmationDescription": { - "message": "这将允许在 MetaMask 中使用此网络。" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask 不验证自定义网络。" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "了解 $1。", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "欺诈和网络安全风险", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "允许此网站添加一个网络到MetaMask上?" - }, "addEthereumChainWarningModalHeader": { "message": "仅当您确定可以信任此 RPC 提供商时才能添加它。$1", "description": "$1 is addEthereumChainWarningModalHeaderPartTwo passed separately so that it can be bolded" @@ -4858,9 +4841,6 @@ "message": "联系 $1 的创建者以获得进一步支持。", "description": "This is shown when the insight snap throws an error. $1 is the snap name" }, - "someNetworksMayPoseSecurity": { - "message": "某些网络可能会带来安全和/或隐私风险。在添加和使用网络之前,请先了解风险。" - }, "somethingDoesntLookRight": { "message": "有什么不对劲吗?$1", "description": "A false positive message for users to contact support. $1 is a link to the support page." @@ -6007,9 +5987,6 @@ "viewActivity": { "message": "查看活动" }, - "viewAllDetails": { - "message": "查看所有详情" - }, "viewAllQuotes": { "message": "查看所有报价" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 7cdfa8e28add..7a7fdb68cf1f 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -42,23 +42,6 @@ "addContact": { "message": "新增合約" }, - "addEthereumChainConfirmationDescription": { - "message": "這會允許在 MetaMask 內使用這個網路。" - }, - "addEthereumChainConfirmationRisks": { - "message": "MetaMask 不會對自訂的網路做驗證。" - }, - "addEthereumChainConfirmationRisksLearnMore": { - "message": "了解更多關於$1的事。", - "description": "$1 is a link with text that is provided by the 'addEthereumChainConfirmationRisksLearnMoreLink' key" - }, - "addEthereumChainConfirmationRisksLearnMoreLink": { - "message": "詐騙與網路安全風險", - "description": "Link text for the 'addEthereumChainConfirmationRisksLearnMore' translation key" - }, - "addEthereumChainConfirmationTitle": { - "message": "允許這個網站新增一個網路?" - }, "addFriendsAndAddresses": { "message": "新增朋友和您信任的位址" }, @@ -1370,9 +1353,6 @@ "userName": { "message": "使用者名稱" }, - "viewAllDetails": { - "message": "查看所有詳情" - }, "viewContact": { "message": "觀看聯絡資訊" }, diff --git a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js index b992925ffc7a..584408134f1a 100644 --- a/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js +++ b/test/e2e/tests/dapp-interactions/dapp-interactions.spec.js @@ -31,7 +31,7 @@ describe('Dapp interactions', function () { await driver.switchToWindowWithTitle(WINDOW_TITLES.Dialog); await unlockWallet(driver); const notification = await driver.isElementPresent({ - text: 'Allow this site to add a network?', + text: 'Add Localhost 8546', tag: 'h3', }); diff --git a/test/e2e/tests/network/add-custom-network.spec.js b/test/e2e/tests/network/add-custom-network.spec.js index dc8f38e1168c..d24beb431c1c 100644 --- a/test/e2e/tests/network/add-custom-network.spec.js +++ b/test/e2e/tests/network/add-custom-network.spec.js @@ -119,9 +119,7 @@ const inputData = { }; describe('Custom network', function () { - const chainID = '42161'; const networkURL = 'https://arbitrum-mainnet.infura.io'; - const networkNAME = 'Arbitrum One'; const currencySYMBOL = 'ETH'; const blockExplorerURL = 'https://explorer.arbitrum.io'; @@ -456,52 +454,29 @@ describe('Custom network', function () { text: 'Add', }); - // verify network details - const title = await driver.findElement({ - tag: 'span', - text: 'Arbitrum One', - }); - - assert.equal( - await title.getText(), - 'Arbitrum One', - 'Title of popup should be selected network', + const [currencySymbol, networkUrl] = await driver.findElements( + '.definition-list dd', ); - - const [networkName, networkUrl, chainIdElement, currencySymbol] = - await driver.findElements('.definition-list dd'); - assert.equal( - await networkName.getText(), - networkNAME, - 'Network name is not correctly displayed', + await currencySymbol.getText(), + currencySYMBOL, + 'Currency symbol is not correctly displayed', ); assert.equal( await networkUrl.getText(), networkURL, 'Network Url is not correctly displayed', ); - assert.equal( - await chainIdElement.getText(), - chainID.toString(), - 'Chain Id is not correctly displayed', - ); - assert.equal( - await currencySymbol.getText(), - currencySYMBOL, - 'Currency symbol is not correctly displayed', - ); - await driver.clickElement({ tag: 'a', text: 'View all details' }); + await driver.clickElement({ tag: 'a', text: 'See details' }); const networkDetailsLabels = await driver.findElements('dd'); assert.equal( - await networkDetailsLabels[8].getText(), + await networkDetailsLabels[4].getText(), blockExplorerURL, 'Block Explorer URL is not correct', ); - await driver.clickElement({ tag: 'button', text: 'Close' }); await driver.clickElement({ tag: 'button', text: 'Approve' }); // verify network switched diff --git a/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js b/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js index 719f8cbdc16b..f40fd68f9566 100644 --- a/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js +++ b/test/e2e/tests/ppom/ppom-blockaid-alert-networks-support.spec.js @@ -114,7 +114,7 @@ describe('PPOM Blockaid Alert - Multiple Networks Support @no-mmi', function () text: 'Add', }); - await driver.clickElement({ tag: 'a', text: 'View all details' }); + await driver.clickElement({ tag: 'a', text: 'See details' }); await driver.clickElement({ tag: 'button', text: 'Close' }); await driver.clickElement({ tag: 'button', text: 'Approve' }); diff --git a/ui/components/ui/definition-list/definition-list.js b/ui/components/ui/definition-list/definition-list.js index 84a23325b37a..84d3f48135ab 100644 --- a/ui/components/ui/definition-list/definition-list.js +++ b/ui/components/ui/definition-list/definition-list.js @@ -32,7 +32,7 @@ export default function DefinitionList({ {Object.entries(dictionary).map(([term, definition]) => ( setIsPopoverOpen(true)} > - {t(process.env.CHAIN_PERMISSIONS ? 'seeDetails' : 'viewAllDetails')} + {t('seeDetails')} ); - const renderPopover = () => - isPopoverOpen && ( - setIsPopoverOpen(false)} - footer={ - - } - > - - {renderDefinitionList(true)} - - - ); - const renderContent = () => { - if (process.env.CHAIN_PERMISSIONS) { - return isPopoverOpen ? ( - renderDefinitionList(true) - ) : ( - <> - {renderDefinitionList(false)} - {renderButton()} - - ); - } - return ( + return isPopoverOpen ? ( + renderDefinitionList(true) + ) : ( <> {renderDefinitionList(false)} {renderButton()} - {renderPopover()} ); }; return ( - {templatedValues.networkDisplay && !process.env.CHAIN_PERMISSIONS ? ( - - - - ) : null} {isSnapCustomUIDialog ? ( :last-child { - margin-bottom: 16px; + margin-top: auto; } } diff --git a/ui/pages/confirmations/confirmation/templates/__snapshots__/add-ethereum-chain.test.js.snap b/ui/pages/confirmations/confirmation/templates/__snapshots__/add-ethereum-chain.test.js.snap index 38bdc74279f8..d29769f0ca7f 100644 --- a/ui/pages/confirmations/confirmation/templates/__snapshots__/add-ethereum-chain.test.js.snap +++ b/ui/pages/confirmations/confirmation/templates/__snapshots__/add-ethereum-chain.test.js.snap @@ -6,94 +6,52 @@ exports[`add-ethereum-chain confirmation should match snapshot 1`] = ` class="confirmation-page" >
-
-
-
- T -
- - Test initial state - - -
-

Update Test initial state

This site is requesting to update your default network URL. You can edit defaults and network information any time.
-
- - MetaMask does not verify custom networks. - - - - Learn about - - scams and network security risks - - . - - -
- Network name + Currency symbol
- Test chain + TST
Network URL
@@ -107,75 +65,41 @@ exports[`add-ethereum-chain confirmation should match snapshot 1`] = ` >
https://rpcurl.test.chain
-
- Chain ID -
-
- -
-
-
-
- 39321 -
-
- Currency symbol -
-
- -
-
-
-
- TST -
- View all details + See details
+
+ + + Beware of + + network scams and security risks + + . + + +