From 6d34630bb78be87da26ee45efad4fcf29d332b87 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Thu, 8 Feb 2024 15:22:18 +0100 Subject: [PATCH 01/55] v11.11.0 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29ffea7f9a81..512f82f69631 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] +## [11.11.0] + ## [11.8.0] ### Added - Enhanced the Networks List with drag and drop functionality ([#21163] (https://github.com/MetaMask/metamask-extension/pull/21163)) @@ -4295,7 +4297,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.8.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...HEAD +[11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.8.0...v11.11.0 [11.8.0]: https://github.com/MetaMask/metamask-extension/compare/v11.7.5...v11.8.0 [11.7.5]: https://github.com/MetaMask/metamask-extension/compare/v11.7.4...v11.7.5 [11.7.4]: https://github.com/MetaMask/metamask-extension/compare/v11.7.3...v11.7.4 diff --git a/package.json b/package.json index 28f7848a17b3..4ce470fcee89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.8.0", + "version": "11.11.0", "private": true, "repository": { "type": "git", From 8753ce4ed6897fa3c2a4b9a873589391cd95a4d2 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 21 Feb 2024 06:13:00 -0330 Subject: [PATCH 02/55] Run yarn lavamoat:auto after merge of master (v11.10.0) into v11.11.0 --- lavamoat/browserify/beta/policy.json | 46 +++-- lavamoat/browserify/desktop/policy.json | 46 +++-- lavamoat/browserify/flask/policy.json | 46 +++-- lavamoat/browserify/main/policy.json | 46 +++-- lavamoat/browserify/mmi/policy.json | 46 +++-- lavamoat/build-system/policy.json | 228 +++++++++--------------- 6 files changed, 237 insertions(+), 221 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 0dd7391fc4a7..204a15a02193 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1047,9 +1047,10 @@ }, "@metamask/eth-token-tracker>deep-equal": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, - "@metamask/eth-token-tracker>deep-equal>isarray": true, "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": true, "@metamask/eth-token-tracker>deep-equal>which-collection": true, "@ngraveio/bc-ur>assert>object-is": true, @@ -1061,7 +1062,6 @@ "string.prototype.matchall>es-abstract>is-array-buffer": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>es-abstract>is-shared-array-buffer": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>get-intrinsic": true, "string.prototype.matchall>regexp.prototype.flags": true, "string.prototype.matchall>side-channel": true @@ -1069,9 +1069,9 @@ }, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": true, "browserify>process": true, "browserify>util>is-arguments": true, @@ -2312,9 +2312,7 @@ "clearTimeout": true, "console.error": true, "document": true, - "new": true, - "setTimeout": true, - "target": true + "setTimeout": true }, "packages": { "browserify>process": true @@ -3419,9 +3417,7 @@ "globals": { "AbortController": true, "AggregateError": true, - "Blob": true, - "new": true, - "target": true + "Blob": true }, "packages": { "browserify>buffer": true, @@ -3474,9 +3470,9 @@ }, "gulp>vinyl-fs>object.assign": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "string.prototype.matchall>call-bind": true, "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>has-symbols": true } }, @@ -4188,23 +4184,40 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties": { + "string.prototype.matchall>call-bind>es-define-property": { "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>es-abstract>object-keys": true + "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties>define-data-property": { + "string.prototype.matchall>call-bind>set-function-length": { "packages": { + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>define-properties>define-data-property": true, "string.prototype.matchall>es-abstract>gopd": true, "string.prototype.matchall>es-abstract>has-property-descriptors": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>define-properties": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "string.prototype.matchall>define-properties>define-data-property": true, + "string.prototype.matchall>es-abstract>has-property-descriptors": true + } + }, + "string.prototype.matchall>define-properties>define-data-property": { + "packages": { + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, "string.prototype.matchall>es-abstract>array-buffer-byte-length": { "packages": { "string.prototype.matchall>call-bind": true, @@ -4223,7 +4236,7 @@ }, "string.prototype.matchall>es-abstract>has-property-descriptors": { "packages": { - "string.prototype.matchall>get-intrinsic": true + "string.prototype.matchall>call-bind>es-define-property": true } }, "string.prototype.matchall>es-abstract>is-array-buffer": { @@ -4258,6 +4271,7 @@ "packages": { "browserify>has>function-bind": true, "depcheck>is-core-module>hasown": true, + "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>has-symbols": true } diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 57ac99027ce2..a45dd98b61ce 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1124,9 +1124,10 @@ }, "@metamask/eth-token-tracker>deep-equal": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, - "@metamask/eth-token-tracker>deep-equal>isarray": true, "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": true, "@metamask/eth-token-tracker>deep-equal>which-collection": true, "@ngraveio/bc-ur>assert>object-is": true, @@ -1138,7 +1139,6 @@ "string.prototype.matchall>es-abstract>is-array-buffer": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>es-abstract>is-shared-array-buffer": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>get-intrinsic": true, "string.prototype.matchall>regexp.prototype.flags": true, "string.prototype.matchall>side-channel": true @@ -1146,9 +1146,9 @@ }, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": true, "browserify>process": true, "browserify>util>is-arguments": true, @@ -2564,9 +2564,7 @@ "clearTimeout": true, "console.error": true, "document": true, - "new": true, - "setTimeout": true, - "target": true + "setTimeout": true }, "packages": { "browserify>process": true @@ -3676,9 +3674,7 @@ "globals": { "AbortController": true, "AggregateError": true, - "Blob": true, - "new": true, - "target": true + "Blob": true }, "packages": { "browserify>buffer": true, @@ -3731,9 +3727,9 @@ }, "gulp>vinyl-fs>object.assign": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "string.prototype.matchall>call-bind": true, "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>has-symbols": true } }, @@ -4554,23 +4550,40 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties": { + "string.prototype.matchall>call-bind>es-define-property": { "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>es-abstract>object-keys": true + "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties>define-data-property": { + "string.prototype.matchall>call-bind>set-function-length": { "packages": { + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>define-properties>define-data-property": true, "string.prototype.matchall>es-abstract>gopd": true, "string.prototype.matchall>es-abstract>has-property-descriptors": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>define-properties": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "string.prototype.matchall>define-properties>define-data-property": true, + "string.prototype.matchall>es-abstract>has-property-descriptors": true + } + }, + "string.prototype.matchall>define-properties>define-data-property": { + "packages": { + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, "string.prototype.matchall>es-abstract>array-buffer-byte-length": { "packages": { "string.prototype.matchall>call-bind": true, @@ -4589,7 +4602,7 @@ }, "string.prototype.matchall>es-abstract>has-property-descriptors": { "packages": { - "string.prototype.matchall>get-intrinsic": true + "string.prototype.matchall>call-bind>es-define-property": true } }, "string.prototype.matchall>es-abstract>is-array-buffer": { @@ -4624,6 +4637,7 @@ "packages": { "browserify>has>function-bind": true, "depcheck>is-core-module>hasown": true, + "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>has-symbols": true } diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index f3d8b3921e54..0df8cc7352d7 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1124,9 +1124,10 @@ }, "@metamask/eth-token-tracker>deep-equal": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, - "@metamask/eth-token-tracker>deep-equal>isarray": true, "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": true, "@metamask/eth-token-tracker>deep-equal>which-collection": true, "@ngraveio/bc-ur>assert>object-is": true, @@ -1138,7 +1139,6 @@ "string.prototype.matchall>es-abstract>is-array-buffer": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>es-abstract>is-shared-array-buffer": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>get-intrinsic": true, "string.prototype.matchall>regexp.prototype.flags": true, "string.prototype.matchall>side-channel": true @@ -1146,9 +1146,9 @@ }, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": true, "browserify>process": true, "browserify>util>is-arguments": true, @@ -2600,9 +2600,7 @@ "clearTimeout": true, "console.error": true, "document": true, - "new": true, - "setTimeout": true, - "target": true + "setTimeout": true }, "packages": { "browserify>process": true @@ -3712,9 +3710,7 @@ "globals": { "AbortController": true, "AggregateError": true, - "Blob": true, - "new": true, - "target": true + "Blob": true }, "packages": { "browserify>buffer": true, @@ -3767,9 +3763,9 @@ }, "gulp>vinyl-fs>object.assign": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "string.prototype.matchall>call-bind": true, "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>has-symbols": true } }, @@ -4590,23 +4586,40 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties": { + "string.prototype.matchall>call-bind>es-define-property": { "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>es-abstract>object-keys": true + "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties>define-data-property": { + "string.prototype.matchall>call-bind>set-function-length": { "packages": { + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>define-properties>define-data-property": true, "string.prototype.matchall>es-abstract>gopd": true, "string.prototype.matchall>es-abstract>has-property-descriptors": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>define-properties": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "string.prototype.matchall>define-properties>define-data-property": true, + "string.prototype.matchall>es-abstract>has-property-descriptors": true + } + }, + "string.prototype.matchall>define-properties>define-data-property": { + "packages": { + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, "string.prototype.matchall>es-abstract>array-buffer-byte-length": { "packages": { "string.prototype.matchall>call-bind": true, @@ -4625,7 +4638,7 @@ }, "string.prototype.matchall>es-abstract>has-property-descriptors": { "packages": { - "string.prototype.matchall>get-intrinsic": true + "string.prototype.matchall>call-bind>es-define-property": true } }, "string.prototype.matchall>es-abstract>is-array-buffer": { @@ -4660,6 +4673,7 @@ "packages": { "browserify>has>function-bind": true, "depcheck>is-core-module>hasown": true, + "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>has-symbols": true } diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index de44e62dc542..9a90922c34fa 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1047,9 +1047,10 @@ }, "@metamask/eth-token-tracker>deep-equal": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, - "@metamask/eth-token-tracker>deep-equal>isarray": true, "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": true, "@metamask/eth-token-tracker>deep-equal>which-collection": true, "@ngraveio/bc-ur>assert>object-is": true, @@ -1061,7 +1062,6 @@ "string.prototype.matchall>es-abstract>is-array-buffer": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>es-abstract>is-shared-array-buffer": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>get-intrinsic": true, "string.prototype.matchall>regexp.prototype.flags": true, "string.prototype.matchall>side-channel": true @@ -1069,9 +1069,9 @@ }, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": true, "browserify>process": true, "browserify>util>is-arguments": true, @@ -2523,9 +2523,7 @@ "clearTimeout": true, "console.error": true, "document": true, - "new": true, - "setTimeout": true, - "target": true + "setTimeout": true }, "packages": { "browserify>process": true @@ -3635,9 +3633,7 @@ "globals": { "AbortController": true, "AggregateError": true, - "Blob": true, - "new": true, - "target": true + "Blob": true }, "packages": { "browserify>buffer": true, @@ -3690,9 +3686,9 @@ }, "gulp>vinyl-fs>object.assign": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "string.prototype.matchall>call-bind": true, "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>has-symbols": true } }, @@ -4513,23 +4509,40 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties": { + "string.prototype.matchall>call-bind>es-define-property": { "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>es-abstract>object-keys": true + "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties>define-data-property": { + "string.prototype.matchall>call-bind>set-function-length": { "packages": { + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>define-properties>define-data-property": true, "string.prototype.matchall>es-abstract>gopd": true, "string.prototype.matchall>es-abstract>has-property-descriptors": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>define-properties": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "string.prototype.matchall>define-properties>define-data-property": true, + "string.prototype.matchall>es-abstract>has-property-descriptors": true + } + }, + "string.prototype.matchall>define-properties>define-data-property": { + "packages": { + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, "string.prototype.matchall>es-abstract>array-buffer-byte-length": { "packages": { "string.prototype.matchall>call-bind": true, @@ -4548,7 +4561,7 @@ }, "string.prototype.matchall>es-abstract>has-property-descriptors": { "packages": { - "string.prototype.matchall>get-intrinsic": true + "string.prototype.matchall>call-bind>es-define-property": true } }, "string.prototype.matchall>es-abstract>is-array-buffer": { @@ -4583,6 +4596,7 @@ "packages": { "browserify>has>function-bind": true, "depcheck>is-core-module>hasown": true, + "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>has-symbols": true } diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index d760e5d301f7..f650f75b366c 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1179,9 +1179,10 @@ }, "@metamask/eth-token-tracker>deep-equal": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": true, "@metamask/eth-token-tracker>deep-equal>is-date-object": true, - "@metamask/eth-token-tracker>deep-equal>isarray": true, "@metamask/eth-token-tracker>deep-equal>which-boxed-primitive": true, "@metamask/eth-token-tracker>deep-equal>which-collection": true, "@ngraveio/bc-ur>assert>object-is": true, @@ -1193,7 +1194,6 @@ "string.prototype.matchall>es-abstract>is-array-buffer": true, "string.prototype.matchall>es-abstract>is-regex": true, "string.prototype.matchall>es-abstract>is-shared-array-buffer": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>get-intrinsic": true, "string.prototype.matchall>regexp.prototype.flags": true, "string.prototype.matchall>side-channel": true @@ -1201,9 +1201,9 @@ }, "@metamask/eth-token-tracker>deep-equal>es-get-iterator": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-map": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>is-set": true, - "@metamask/eth-token-tracker>deep-equal>es-get-iterator>isarray": true, "@metamask/eth-token-tracker>deep-equal>es-get-iterator>stop-iteration-iterator": true, "browserify>process": true, "browserify>util>is-arguments": true, @@ -2619,9 +2619,7 @@ "clearTimeout": true, "console.error": true, "document": true, - "new": true, - "setTimeout": true, - "target": true + "setTimeout": true }, "packages": { "browserify>process": true @@ -3731,9 +3729,7 @@ "globals": { "AbortController": true, "AggregateError": true, - "Blob": true, - "new": true, - "target": true + "Blob": true }, "packages": { "browserify>buffer": true, @@ -3786,9 +3782,9 @@ }, "gulp>vinyl-fs>object.assign": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "string.prototype.matchall>call-bind": true, "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>has-symbols": true } }, @@ -4585,23 +4581,40 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties": { + "string.prototype.matchall>call-bind>es-define-property": { "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>es-abstract>object-keys": true + "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties>define-data-property": { + "string.prototype.matchall>call-bind>set-function-length": { "packages": { + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>define-properties>define-data-property": true, "string.prototype.matchall>es-abstract>gopd": true, "string.prototype.matchall>es-abstract>has-property-descriptors": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>define-properties": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "string.prototype.matchall>define-properties>define-data-property": true, + "string.prototype.matchall>es-abstract>has-property-descriptors": true + } + }, + "string.prototype.matchall>define-properties>define-data-property": { + "packages": { + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, "string.prototype.matchall>es-abstract>array-buffer-byte-length": { "packages": { "string.prototype.matchall>call-bind": true, @@ -4620,7 +4633,7 @@ }, "string.prototype.matchall>es-abstract>has-property-descriptors": { "packages": { - "string.prototype.matchall>get-intrinsic": true + "string.prototype.matchall>call-bind>es-define-property": true } }, "string.prototype.matchall>es-abstract>is-array-buffer": { @@ -4655,6 +4668,7 @@ "packages": { "browserify>has>function-bind": true, "depcheck>is-core-module>hasown": true, + "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>has-symbols": true } diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 7f62df970a5b..92489d59d8d6 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1168,13 +1168,13 @@ "packages": { "@lavamoat/lavapack>combine-source-map": true, "@lavamoat/lavapack>convert-source-map": true, + "@lavamoat/lavapack>json-stable-stringify": true, + "@lavamoat/lavapack>lavamoat-core": true, "@lavamoat/lavapack>readable-stream": true, - "@lavamoat/lavapack>through2": true, "@lavamoat/lavapack>umd": true, "browserify>JSONStream": true, "eslint>espree": true, - "lavamoat>json-stable-stringify": true, - "lavamoat>lavamoat-core": true + "through2": true } }, "@lavamoat/lavapack>combine-source-map": { @@ -1208,71 +1208,71 @@ "value": true } }, - "@lavamoat/lavapack>readable-stream": { + "@lavamoat/lavapack>json-stable-stringify": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>isarray": true, + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "lavamoat>json-stable-stringify>jsonify": true, + "string.prototype.matchall>call-bind": true + } + }, + "@lavamoat/lavapack>lavamoat-core": { "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true + "events": true, + "fs.readFileSync": true, + "node:fs/promises.readFile": true, + "node:fs/promises.writeFile": true, + "path.extname": true, + "path.join": true }, "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true + "__dirname": true, + "ast": true, + "console.error": true, + "console.warn": true, + "content": true, + "define": true, + "file": true, + "importMap": true, + "moduleInitializer": true, + "packageName": true, + "specifier": true, + "type": true }, "packages": { - "browserify>string_decoder": true, - "pumpify>inherits": true, - "readable-stream>util-deprecate": true + "@lavamoat/lavapack>json-stable-stringify": true, + "@lavamoat/lavapack>lavamoat-core>lavamoat-tofu": true, + "lavamoat>lavamoat-core>merge-deep": true } }, - "@lavamoat/lavapack>through2": { - "builtin": { - "util.inherits": true - }, + "@lavamoat/lavapack>lavamoat-core>lavamoat-tofu": { "globals": { - "process.nextTick": true + "console.log": true }, "packages": { - "@lavamoat/lavapack>through2>readable-stream": true, - "watchify>xtend": true + "@babel/core>@babel/parser": true, + "depcheck>@babel/traverse": true } }, - "@lavamoat/lavapack>through2>readable-stream": { + "@lavamoat/lavapack>readable-stream": { "builtin": { + "buffer.Buffer": true, "events.EventEmitter": true, "stream": true, "util": true }, "globals": { - "process.browser": true, "process.env.READABLE_STREAM": true, + "process.nextTick": true, "process.stderr": true, - "process.stdout": true, - "process.version.slice": true, - "setImmediate": true + "process.stdout": true }, "packages": { - "@lavamoat/lavapack>through2>readable-stream>safe-buffer": true, - "@lavamoat/lavapack>through2>readable-stream>string_decoder": true, + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, "readable-stream>util-deprecate": true } }, - "@lavamoat/lavapack>through2>readable-stream>safe-buffer": { - "builtin": { - "buffer": true - } - }, - "@lavamoat/lavapack>through2>readable-stream>string_decoder": { - "packages": { - "@lavamoat/lavapack>through2>readable-stream>safe-buffer": true - } - }, "@metamask/build-utils": { "packages": { "@metamask/utils": true @@ -1465,9 +1465,7 @@ "globals": { "console.log": true, "console.warn": true, - "new": true, - "process": true, - "target": true + "process": true }, "packages": { "@typescript-eslint/eslint-plugin>tsutils": true, @@ -4256,7 +4254,7 @@ }, "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>isobject": { "packages": { - "readable-stream>isarray": true + "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>isobject>isarray": true } }, "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>randomatic": { @@ -4739,7 +4737,7 @@ }, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>unset-value>has-value>isobject": { "packages": { - "readable-stream>isarray": true + "gulp-watch>chokidar>braces>snapdragon>base>cache-base>unset-value>has-value>isobject>isarray": true } }, "gulp-watch>chokidar>braces>snapdragon>base>class-utils": { @@ -5862,8 +5860,8 @@ }, "gulp>vinyl-fs>glob-stream>unique-stream": { "packages": { - "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter": true, - "lavamoat>json-stable-stringify": true + "@lavamoat/lavapack>json-stable-stringify": true, + "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter": true } }, "gulp>vinyl-fs>glob-stream>unique-stream>through2-filter": { @@ -5911,9 +5909,9 @@ }, "gulp>vinyl-fs>object.assign": { "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, "string.prototype.matchall>call-bind": true, "string.prototype.matchall>define-properties": true, - "string.prototype.matchall>es-abstract>object-keys": true, "string.prototype.matchall>has-symbols": true } }, @@ -6105,81 +6103,47 @@ }, "packages": { "@lavamoat/lavapack": true, + "@lavamoat/lavapack>json-stable-stringify": true, + "@lavamoat/lavapack>lavamoat-core": true, "browserify>browser-resolve": true, - "browserify>concat-stream": true, "duplexify": true, + "lavamoat-browserify>concat-stream": true, "lavamoat-browserify>readable-stream": true, - "lavamoat-browserify>through2": true, "lavamoat>@lavamoat/aa": true, - "lavamoat>json-stable-stringify": true, - "lavamoat>lavamoat-core": true + "through2": true } }, - "lavamoat-browserify>readable-stream": { - "builtin": { - "buffer.Buffer": true, - "events.EventEmitter": true, - "stream": true, - "util": true - }, + "lavamoat-browserify>concat-stream": { "globals": { - "process.env.READABLE_STREAM": true, - "process.nextTick": true, - "process.stderr": true, - "process.stdout": true + "Buffer.concat": true, + "Buffer.isBuffer": true }, "packages": { - "browserify>string_decoder": true, + "browserify>concat-stream>typedarray": true, + "lavamoat-browserify>readable-stream": true, "pumpify>inherits": true, - "readable-stream>util-deprecate": true - } - }, - "lavamoat-browserify>through2": { - "builtin": { - "util.inherits": true - }, - "globals": { - "process.nextTick": true - }, - "packages": { - "lavamoat-browserify>through2>readable-stream": true, - "watchify>xtend": true + "terser>source-map-support>buffer-from": true } }, - "lavamoat-browserify>through2>readable-stream": { + "lavamoat-browserify>readable-stream": { "builtin": { + "buffer.Buffer": true, "events.EventEmitter": true, "stream": true, "util": true }, "globals": { - "process.browser": true, "process.env.READABLE_STREAM": true, + "process.nextTick": true, "process.stderr": true, - "process.stdout": true, - "process.version.slice": true, - "setImmediate": true + "process.stdout": true }, "packages": { - "lavamoat-browserify>through2>readable-stream>safe-buffer": true, - "lavamoat-browserify>through2>readable-stream>string_decoder": true, + "browserify>string_decoder": true, "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>process-nextick-args": true, "readable-stream>util-deprecate": true } }, - "lavamoat-browserify>through2>readable-stream>safe-buffer": { - "builtin": { - "buffer": true - } - }, - "lavamoat-browserify>through2>readable-stream>string_decoder": { - "packages": { - "lavamoat-browserify>through2>readable-stream>safe-buffer": true - } - }, "lavamoat>@lavamoat/aa": { "builtin": { "fs.readFileSync": true, @@ -6191,31 +6155,6 @@ "brfs>resolve": true } }, - "lavamoat>json-stable-stringify": { - "packages": { - "lavamoat>json-stable-stringify>jsonify": true - } - }, - "lavamoat>lavamoat-core": { - "builtin": { - "events": true, - "fs.readFileSync": true, - "node:fs/promises.readFile": true, - "path.extname": true, - "path.join": true - }, - "globals": { - "__dirname": true, - "console.error": true, - "console.warn": true, - "define": true - }, - "packages": { - "lavamoat>json-stable-stringify": true, - "lavamoat>lavamoat-core>merge-deep": true, - "lavamoat>lavamoat-tofu": true - } - }, "lavamoat>lavamoat-core>merge-deep": { "packages": { "gulp-zip>plugin-error>arr-union": true, @@ -6280,15 +6219,6 @@ "browserify>insert-module-globals>is-buffer": true } }, - "lavamoat>lavamoat-tofu": { - "globals": { - "console.log": true - }, - "packages": { - "@babel/core>@babel/parser": true, - "depcheck>@babel/traverse": true - } - }, "lodash": { "globals": { "define": true @@ -7116,7 +7046,6 @@ "moveSyntheticComments": true, "navigator": true, "needsParentheses": true, - "new": true, "newCaseClauseTracker": true, "newPrivateEnvironment": true, "noEmitNotification": true, @@ -7254,7 +7183,6 @@ "syntaxMayBeASICandidate": true, "syntaxRequiresTrailingSemicolonOrASI": true, "sysLog": true, - "target": true, "targetOptionDeclaration": true, "templateObjectHelper": true, "testFormatSettings": true, @@ -7641,23 +7569,40 @@ "string.prototype.matchall>call-bind": { "packages": { "browserify>has>function-bind": true, + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>call-bind>set-function-length": true, "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties": { + "string.prototype.matchall>call-bind>es-define-property": { "packages": { - "string.prototype.matchall>define-properties>define-data-property": true, - "string.prototype.matchall>es-abstract>has-property-descriptors": true, - "string.prototype.matchall>es-abstract>object-keys": true + "string.prototype.matchall>get-intrinsic": true } }, - "string.prototype.matchall>define-properties>define-data-property": { + "string.prototype.matchall>call-bind>set-function-length": { "packages": { + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>define-properties>define-data-property": true, "string.prototype.matchall>es-abstract>gopd": true, "string.prototype.matchall>es-abstract>has-property-descriptors": true, "string.prototype.matchall>get-intrinsic": true } }, + "string.prototype.matchall>define-properties": { + "packages": { + "@lavamoat/lavapack>json-stable-stringify>object-keys": true, + "string.prototype.matchall>define-properties>define-data-property": true, + "string.prototype.matchall>es-abstract>has-property-descriptors": true + } + }, + "string.prototype.matchall>define-properties>define-data-property": { + "packages": { + "string.prototype.matchall>call-bind>es-define-property": true, + "string.prototype.matchall>call-bind>es-errors": true, + "string.prototype.matchall>es-abstract>gopd": true + } + }, "string.prototype.matchall>es-abstract": { "packages": { "brfs>static-module>object-inspect": true, @@ -7704,7 +7649,7 @@ }, "string.prototype.matchall>es-abstract>has-property-descriptors": { "packages": { - "string.prototype.matchall>get-intrinsic": true + "string.prototype.matchall>call-bind>es-define-property": true } }, "string.prototype.matchall>es-abstract>is-callable": { @@ -7741,6 +7686,7 @@ "packages": { "browserify>has>function-bind": true, "depcheck>is-core-module>hasown": true, + "string.prototype.matchall>call-bind>es-errors": true, "string.prototype.matchall>es-abstract>has-proto": true, "string.prototype.matchall>has-symbols": true } From ec7e595308a3b8789b5f2c646bfe9279ae0b704a Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:58:48 +0100 Subject: [PATCH 03/55] test: fix several ppom testcases due to description change (#23052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** It seems that the description response for the malicious mocked requests has changed in a recent update. This PR aims to fix the e2e tests. This also reveals the strong need for using a stable version of the cdn, by: - Either using the cdn test version of ppom (stable), like we used to do --> that was changed due to some issue Blockaid had on their end - Or mocking the cdn responses and keep them always the same --> to investigate if this is doable, since the responses that we get are in a "weird format" (see example below) ![Screenshot from 2024-02-19 19-23-25](https://github.com/MetaMask/metamask-extension/assets/54408225/54589804-2c9f-40c7-8f67-2ff800f0b0be) Another scenario to explore for some of these specs, would be to see if we can inject the files directly in the ppomDB. In the same way we initialize the wallet with a certain state, we could initialize the wallet with the ppomDB prefilled in storage. This PR however, aims to unblock ci in the fastes possible way ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/23053 ## **Manual testing steps** 1. Check ci or run them locally ## **Screenshots/Recordings** ### **Before** ![Screenshot from 2024-02-19 19-04-44](https://github.com/MetaMask/metamask-extension/assets/54408225/248ae58c-fb40-4531-8028-a3e218ed44b3) ### **After** ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [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. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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. --- .../ppom-blockaid-alert-erc20-approval.spec.js | 2 +- .../ppom-blockaid-alert-erc20-transfer.spec.js | 2 +- .../ppom-blockaid-alert-networks-support.spec.js | 13 +++++-------- test/e2e/tests/ppom-blockaid-alert.spec.js | 3 ++- .../ppom-blockaid-setApprovalForAll-farming.spec.js | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js index 6afd95478ef1..e9d19244551f 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js @@ -232,7 +232,7 @@ describe('PPOM Blockaid Alert - Malicious ERC20 Approval @no-mmi', function () { const expectedTitle = 'This is a deceptive request'; const expectedDescription = - 'If you approve this request, a third party known for scams might take all your assets.'; + 'If you approve this request, you might lose your assets.'; // Click TestDapp button to send JSON-RPC request await driver.clickElement('#maliciousApprovalButton'); diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js index 3777c83af37f..38dbc1b7ffe7 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js @@ -180,7 +180,7 @@ describe('PPOM Blockaid Alert - Malicious ERC20 Transfer @no-mmi', function () { async ({ driver }) => { const expectedTitle = 'This is a deceptive request'; const expectedDescription = - 'If you approve this request, a third party known for scams will take all your assets.'; + 'If you approve this request, you might lose your assets.'; await unlockWallet(driver); await openDapp(driver); diff --git a/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js b/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js index 88bd449968f8..d41c74d5cba9 100644 --- a/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js @@ -65,12 +65,9 @@ describe('PPOM Blockaid Alert - Multiple Networks Support @no-mmi', function () async ({ driver }) => { const expectedTitle = 'This is a deceptive request'; - const expectedDescriptionMainnet = + const expectedDescription = 'If you approve this request, you might lose your assets.'; - const expectedDescriptionArbitrum = - 'If you approve this request, a third party known for scams will take all your assets.'; - await unlockWallet(driver); await openDapp(driver); @@ -95,8 +92,8 @@ describe('PPOM Blockaid Alert - Multiple Networks Support @no-mmi', function () `Banner alert not found. Expected Title: ${expectedTitle} \nExpected reason: approval_farming\n`, ); assert( - bannerAlertText.includes(expectedDescriptionMainnet), - `Unexpected banner alert description. Expected: ${expectedDescriptionMainnet} \nExpected reason: approval_farming\n`, + bannerAlertText.includes(expectedDescription), + `Unexpected banner alert description. Expected: ${expectedDescription} \nExpected reason: approval_farming\n`, ); await driver.clickElement({ text: 'Reject', tag: 'button' }); @@ -142,8 +139,8 @@ describe('PPOM Blockaid Alert - Multiple Networks Support @no-mmi', function () `Banner alert not found. Expected Title: ${expectedTitle} \nExpected reason: raw_native_token_transfer\n`, ); assert( - bannerAlertText.includes(expectedDescriptionArbitrum), - `Unexpected banner alert description. Expected: ${expectedDescriptionArbitrum} \nExpected reason: raw_native_token_transfer\n`, + bannerAlertText.includes(expectedDescription), + `Unexpected banner alert description. Expected: ${expectedDescription} \nExpected reason: raw_native_token_transfer\n`, ); }, ); diff --git a/test/e2e/tests/ppom-blockaid-alert.spec.js b/test/e2e/tests/ppom-blockaid-alert.spec.js index 978d6bea57ab..37a06d44050d 100644 --- a/test/e2e/tests/ppom-blockaid-alert.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert.spec.js @@ -287,7 +287,8 @@ describe('Confirmation Security Alert - Blockaid @no-mmi', function () { ); }); - it('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js index 1b2ca4587ae9..7f41d06849e3 100644 --- a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js +++ b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js @@ -270,7 +270,7 @@ describe('PPOM Blockaid Alert - Set Approval to All @no-mmi', function () { const expectedTitle = 'This is a deceptive request'; const expectedDescription = - 'If you approve this request, a third party known for scams might take all your assets.'; + 'If you approve this request, you might lose your assets.'; // Click TestDapp button to send JSON-RPC request await driver.clickElement('#maliciousSetApprovalForAll'); From 75cbce36af2793edfebc5dbf8a5664855f905c65 Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Tue, 13 Feb 2024 17:19:42 +0100 Subject: [PATCH 04/55] Cherry-pick 9c59da5 (#22960) into v11.11.0 fix: Remove unnecessary resolution for socks (#22960) Remove unnecessary resolution for the `socks` package. This removes the risk of the resolution causing problems in future updates, reducing maintenance burdens for the team. --- yarn.lock | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1858a76d6e68..4aa6f7f52147 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20204,6 +20204,16 @@ __metadata: languageName: node linkType: hard +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" + dependencies: + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 1ed81e06721af012306329b31f532b5e24e00cb537be18ddc905a84f19fe8f83a09a1699862bf3a1ec4b9dea93c55a3fa5faf8b5ea380431469df540f38b092c + languageName: node + linkType: hard + "ip@npm:^1.1.4, ip@npm:^1.1.8": version: 1.1.8 resolution: "ip@npm:1.1.8" @@ -21951,6 +21961,13 @@ __metadata: languageName: node linkType: hard +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: bebe7ae829bbd586ce8cbe83501dd8cb8c282c8902a8aeeed0a073a89dc37e8103b1244f3c6acd60278bcbfe12d93a3f83c9ac396868a3b3bbc3c5e5e3b648ef + languageName: node + linkType: hard + "jscodeshift@npm:^0.14.0": version: 0.14.0 resolution: "jscodeshift@npm:0.14.0" @@ -30965,12 +30982,12 @@ __metadata: linkType: hard "socks@npm:^2.6.1, socks@npm:^2.6.2, socks@npm:^2.7.1": - version: 2.7.1 - resolution: "socks@npm:2.7.1" + version: 2.8.0 + resolution: "socks@npm:2.8.0" dependencies: - ip: "npm:^2.0.0" + ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: 5074f7d6a13b3155fa655191df1c7e7a48ce3234b8ccf99afa2ccb56591c195e75e8bb78486f8e9ea8168e95a29573cbaad55b2b5e195160ae4d2ea6811ba833 + checksum: ed0224ce2c7daaa7690cb87cf53d9703ffc4e983aca221f6f5b46767b232658df49494fd86acd0bf97ada6de05248ea8ea625c2343d48155d8463fc40d4a340f languageName: node linkType: hard From b8ef21d05c1e817a78b2148561da7e1ca8236f09 Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Thu, 22 Feb 2024 22:44:18 +0100 Subject: [PATCH 05/55] v11.12.0 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18db909ce3ad..58dde40bc925 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] +## [11.12.0] + ## [11.10.0] ### Added - Added preset network image avatars in the 'Select a network' pop-up ([#22643](https://github.com/MetaMask/metamask-extension/pull/22643)) @@ -4389,7 +4391,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...HEAD +[11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.12.0 [11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 [11.9.5]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...v11.9.5 [11.9.4]: https://github.com/MetaMask/metamask-extension/compare/v11.9.3...v11.9.4 diff --git a/package.json b/package.json index 261b6b384ead..250ce6cfb354 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.10.0", + "version": "11.12.0", "private": true, "repository": { "type": "git", From 4678ea9c7d6948591570c39b06e001c05320f8cc Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 21 Feb 2024 16:08:28 -0330 Subject: [PATCH 06/55] Fix unit test --- .../__snapshots__/blockaid-banner-alert.test.js.snap | 12 ++++++------ .../blockaid-banner-alert.test.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap index 35913c502e5f..c8ba0efbb9dd 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap @@ -50,7 +50,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo Something doesn't look right? @@ -142,7 +142,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? @@ -234,7 +234,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? @@ -327,7 +327,7 @@ exports[`Blockaid Banner Alert should render details section even when features Something doesn't look right? @@ -433,7 +433,7 @@ exports[`Blockaid Banner Alert should render details when provided 1`] = ` Something doesn't look right? @@ -527,7 +527,7 @@ exports[`Blockaid Banner Alert should render link to report url 1`] = ` Something doesn't look right? diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js index 7a3d833fa38e..b34d9d9b0e0a 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js @@ -264,7 +264,7 @@ describe('Blockaid Banner Alert', () => { const elm = getByRole('link', { name: 'Report an issue' }); expect(elm.href).toBe( - 'https://blockaid-false-positive-portal.metamask.io/?data=%7B%22blockaidVersion%22%3A%221.4.0%22%2C%22classification%22%3A%22error%22%2C%22resultType%22%3A%22Error%22%7D&utm_source=metamask-ppom', + 'https://blockaid-false-positive-portal.metamask.io/?data=%7B%22blockaidVersion%22%3A%221.4.1%22%2C%22classification%22%3A%22error%22%2C%22resultType%22%3A%22Error%22%7D&utm_source=metamask-ppom', ); }); }); From b3337bd0792a62255f3ad19400b1fd0e0380be38 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Wed, 21 Feb 2024 23:29:45 +0100 Subject: [PATCH 07/55] test: disable ppom e2e tests temporarily (#23103) Disable ppom tests until cdn responses are mocked. This unblocks ci. --- .../e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js | 3 ++- .../e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js | 3 ++- .../tests/ppom-blockaid-alert-networks-support.spec.js | 3 ++- test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js | 9 ++++++--- .../ppom-blockaid-alert-trade-order-farming.spec.js | 3 ++- .../ppom-blockaid-setApprovalForAll-farming.spec.js | 3 ++- test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js | 3 ++- test/e2e/tests/ppom-toggle-settings.spec.js | 6 ++++-- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js index e9d19244551f..aed08415da79 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js @@ -210,7 +210,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Malicious ERC20 Approval @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js index 38dbc1b7ffe7..5b42a2c2de38 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js @@ -161,7 +161,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Malicious ERC20 Transfer @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js b/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js index d41c74d5cba9..22257978b3bd 100644 --- a/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-networks-support.spec.js @@ -47,7 +47,8 @@ async function mockInfuraWithMaliciousResponses(mockServer) { } describe('PPOM Blockaid Alert - Multiple Networks Support @no-mmi', function () { - it('should show banner alert after switchinig to another supported network', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert after switchinig to another supported network', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js index bf99c19c12c8..d371e3c9f3b7 100644 --- a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js @@ -126,7 +126,8 @@ async function mockInfuraWithFailedResponses(mockServer) { * @see {@link https://wobbly-nutmeg-8a5.notion.site/MM-E2E-Testing-1e51b617f79240a49cd3271565c6e12d} */ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { - it('should not show security alerts for benign requests', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should not show security alerts for benign requests', async function () { await withFixtures( { dapp: true, @@ -158,7 +159,8 @@ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { * 'malicious_domain'. Some other tests are found in other files: * e.g. test/e2e/flask/ppom-blockaid-alert-.spec.js */ - it('should show security alerts for malicious requests', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show security alerts for malicious requests', async function () { await withFixtures( { dapp: true, @@ -201,7 +203,8 @@ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { ); }); - it('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js b/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js index 5ac58bf7a1b8..82bbbf4d3f3a 100644 --- a/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js @@ -90,7 +90,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Set Trade farming order @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js index 7f41d06849e3..94ef3f4a64a5 100644 --- a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js +++ b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js @@ -248,7 +248,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Set Approval to All @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js b/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js index ec763422c112..fd4d3b6c9f05 100644 --- a/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js +++ b/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js @@ -52,7 +52,8 @@ async function mockServerCalls(mockServer) { } describe('PPOM Blockaid Alert - Metrics @no-mmi', function () { - it('Successfully track button toggle on/off', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('Successfully track button toggle on/off', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-toggle-settings.spec.js b/test/e2e/tests/ppom-toggle-settings.spec.js index a355abed98a7..195d55654b7f 100644 --- a/test/e2e/tests/ppom-toggle-settings.spec.js +++ b/test/e2e/tests/ppom-toggle-settings.spec.js @@ -9,7 +9,8 @@ const { const FixtureBuilder = require('../fixture-builder'); describe('PPOM Settings @no-mmi', function () { - it('should not show the PPOM warning when toggle is off', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should not show the PPOM warning when toggle is off', async function () { await withFixtures( { dapp: true, @@ -47,7 +48,8 @@ describe('PPOM Settings @no-mmi', function () { ); }); - it('should show the PPOM warning when the toggle is on', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show the PPOM warning when the toggle is on', async function () { await withFixtures( { dapp: true, From 30108ce90a2a2b0795e4127a45ffd7f358774f3f Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Fri, 23 Feb 2024 21:07:28 +0900 Subject: [PATCH 08/55] fix(deps): socks@2.8.0->2.8.1 (#23143) --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4aa6f7f52147..05bc18a5bfd0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -30982,12 +30982,12 @@ __metadata: linkType: hard "socks@npm:^2.6.1, socks@npm:^2.6.2, socks@npm:^2.7.1": - version: 2.8.0 - resolution: "socks@npm:2.8.0" + version: 2.8.1 + resolution: "socks@npm:2.8.1" dependencies: ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: ed0224ce2c7daaa7690cb87cf53d9703ffc4e983aca221f6f5b46767b232658df49494fd86acd0bf97ada6de05248ea8ea625c2343d48155d8463fc40d4a340f + checksum: a3cc38e0716ab53a2db3fa00c703ca682ad54dbbc9ed4c7461624a999be6fa7cdc79fc904c411618e698d5eff55a55aa6d9329169a7db11636d0200814a2b5aa languageName: node linkType: hard From b5d1949d3ed469caa339ece0143d70e32d96a5de Mon Sep 17 00:00:00 2001 From: Derek Brans Date: Mon, 26 Feb 2024 16:10:25 -0500 Subject: [PATCH 09/55] Cherry-pick PR #23092 to v11.11.0 (#23131) --- shared/constants/first-party-contracts.ts | 38 +++++++++++ ui/hooks/useDisplayName.test.ts | 37 +++++++++-- ui/hooks/useDisplayName.ts | 17 +++-- ui/hooks/useFirstPartyContractName.test.ts | 76 ++++++++++++++++++++++ ui/hooks/useFirstPartyContractName.ts | 25 +++++++ 5 files changed, 182 insertions(+), 11 deletions(-) create mode 100644 shared/constants/first-party-contracts.ts create mode 100644 ui/hooks/useFirstPartyContractName.test.ts create mode 100644 ui/hooks/useFirstPartyContractName.ts diff --git a/shared/constants/first-party-contracts.ts b/shared/constants/first-party-contracts.ts new file mode 100644 index 000000000000..b961895f2841 --- /dev/null +++ b/shared/constants/first-party-contracts.ts @@ -0,0 +1,38 @@ +import { Hex } from '@metamask/utils'; +import { CHAIN_IDS } from './network'; + +/** + * A map of first-party contract names to their addresses on various chains. + */ +export const FIRST_PARTY_CONTRACT_NAMES: Record> = { + 'MetaMask Validator Staking': { + [CHAIN_IDS.MAINNET]: '0xDc71aFFC862fceB6aD32BE58E098423A7727bEbd', + }, + 'MetaMask Pool Staking': { + [CHAIN_IDS.MAINNET]: '0x1f6692E78dDE07FF8da75769B6d7c716215bC7D0', + }, + 'MetaMask Pool Staking (v1)': { + [CHAIN_IDS.MAINNET]: '0xc7bE520a13dC023A1b34C03F4Abdab8A43653F7B', + }, + 'MetaMask Bridge': { + [CHAIN_IDS.MAINNET]: '0x0439e60F02a8900a951603950d8D4527f400C3f1', + [CHAIN_IDS.OPTIMISM]: '0xB90357f2b86dbfD59c3502215d4060f71DF8ca0e', + [CHAIN_IDS.BSC]: '0xaEc23140408534b378bf5832defc426dF8604B59', + [CHAIN_IDS.POLYGON]: '0x3A0b42cE6166abB05d30DdF12E726c95a83D7a16', + [CHAIN_IDS.ZKSYNC_ERA]: '0x357B5935482AD8a4A2e181e0132aBd1882E16520', + [CHAIN_IDS.BASE]: '0xa20ECbC821fB54064aa7B5C6aC81173b8b34Df71', + [CHAIN_IDS.ARBITRUM]: '0x23981fC34e69eeDFE2BD9a0a9fCb0719Fe09DbFC', + [CHAIN_IDS.AVALANCHE]: '0x29106d08382d3c73bF477A94333C61Db1142E1B6', + [CHAIN_IDS.LINEA_MAINNET]: '0xE3d0d2607182Af5B24f5C3C2E4990A053aDd64e3', + }, + 'MetaMask Swaps': { + [CHAIN_IDS.MAINNET]: '0x881D40237659C251811CEC9c364ef91dC08D300C', + [CHAIN_IDS.BSC]: '0x1a1ec25DC08e98e5E93F1104B5e5cdD298707d31', + [CHAIN_IDS.POLYGON]: '0x1a1ec25DC08e98e5E93F1104B5e5cdD298707d31', + [CHAIN_IDS.AVALANCHE]: '0x1a1ec25DC08e98e5E93F1104B5e5cdD298707d31', + [CHAIN_IDS.ARBITRUM]: '0x9dDA6Ef3D919c9bC8885D5560999A3640431e8e6', + [CHAIN_IDS.OPTIMISM]: '0x9dDA6Ef3D919c9bC8885D5560999A3640431e8e6', + [CHAIN_IDS.ZKSYNC_ERA]: '0xf504c1fe13d14DF615E66dcd0ABF39e60c697f34', + [CHAIN_IDS.LINEA_MAINNET]: '0x9dDA6Ef3D919c9bC8885D5560999A3640431e8e6', + }, +}; diff --git a/ui/hooks/useDisplayName.test.ts b/ui/hooks/useDisplayName.test.ts index 7027e73ded73..315c79ee6f96 100644 --- a/ui/hooks/useDisplayName.test.ts +++ b/ui/hooks/useDisplayName.test.ts @@ -2,6 +2,7 @@ import { NameEntry, NameType } from '@metamask/name-controller'; import { getMemoizedMetadataContractName } from '../selectors'; import { useDisplayName } from './useDisplayName'; import { useName } from './useName'; +import { useFirstPartyContractName } from './useFirstPartyContractName'; jest.mock('react-redux', () => ({ useSelector: (selector: any) => selector(), @@ -11,29 +12,37 @@ jest.mock('./useName', () => ({ useName: jest.fn(), })); +jest.mock('./useFirstPartyContractName', () => ({ + useFirstPartyContractName: jest.fn(), +})); + jest.mock('../selectors', () => ({ getMemoizedMetadataContractName: jest.fn(), + getCurrentChainId: jest.fn(), })); const VALUE_MOCK = '0xabc123'; const TYPE_MOCK = NameType.ETHEREUM_ADDRESS; const NAME_MOCK = 'TestName'; const CONTRACT_NAME_MOCK = 'TestContractName'; +const FIRST_PARTY_CONTRACT_NAME_MOCK = 'MetaMask Bridge'; -const NO_CONTRACT_NAME_FOUND_RETURN_VALUE = null; const NO_PETNAME_FOUND_RETURN_VALUE = { name: null, } as NameEntry; +const NO_CONTRACT_NAME_FOUND_RETURN_VALUE = ''; +const NO_FIRST_PARTY_CONTRACT_NAME_FOUND_RETURN_VALUE = null; const PETNAME_FOUND_RETURN_VALUE = { name: NAME_MOCK, } as NameEntry; describe('useDisplayName', () => { + const useNameMock = jest.mocked(useName); const getMemoizedMetadataContractNameMock = jest.mocked( getMemoizedMetadataContractName, ); - const useNameMock = jest.mocked(useName); + const useFirstPartyContractNameMock = jest.mocked(useFirstPartyContractName); beforeEach(() => { jest.resetAllMocks(); @@ -41,6 +50,7 @@ describe('useDisplayName', () => { it('handles no name found', () => { useNameMock.mockReturnValue(NO_PETNAME_FOUND_RETURN_VALUE); + useFirstPartyContractNameMock.mockReturnValue(null); getMemoizedMetadataContractNameMock.mockReturnValue( NO_CONTRACT_NAME_FOUND_RETURN_VALUE, ); @@ -51,8 +61,11 @@ describe('useDisplayName', () => { }); }); - it('prioritizes an existing petname over an existing contract name', () => { + it('prioritizes a petname over all else', () => { useNameMock.mockReturnValue(PETNAME_FOUND_RETURN_VALUE); + useFirstPartyContractNameMock.mockReturnValue( + FIRST_PARTY_CONTRACT_NAME_MOCK, + ); getMemoizedMetadataContractNameMock.mockReturnValue(CONTRACT_NAME_MOCK); expect(useDisplayName(VALUE_MOCK, TYPE_MOCK)).toEqual({ @@ -61,8 +74,24 @@ describe('useDisplayName', () => { }); }); - it('returns a contract name if one is found, if no petname exists', () => { + it('prioritizes a first-party contract name over a contract name', () => { useNameMock.mockReturnValue(NO_PETNAME_FOUND_RETURN_VALUE); + useFirstPartyContractNameMock.mockReturnValue( + FIRST_PARTY_CONTRACT_NAME_MOCK, + ); + getMemoizedMetadataContractNameMock.mockReturnValue(CONTRACT_NAME_MOCK); + + expect(useDisplayName(VALUE_MOCK, TYPE_MOCK)).toEqual({ + name: FIRST_PARTY_CONTRACT_NAME_MOCK, + hasPetname: false, + }); + }); + + it('returns a contract name if no other name is found', () => { + useNameMock.mockReturnValue(NO_PETNAME_FOUND_RETURN_VALUE); + useFirstPartyContractNameMock.mockReturnValue( + NO_FIRST_PARTY_CONTRACT_NAME_FOUND_RETURN_VALUE, + ); getMemoizedMetadataContractNameMock.mockReturnValue(CONTRACT_NAME_MOCK); expect(useDisplayName(VALUE_MOCK, TYPE_MOCK)).toEqual({ diff --git a/ui/hooks/useDisplayName.ts b/ui/hooks/useDisplayName.ts index ca7ff4ba8575..13c3adb3d301 100644 --- a/ui/hooks/useDisplayName.ts +++ b/ui/hooks/useDisplayName.ts @@ -2,6 +2,7 @@ import { NameType } from '@metamask/name-controller'; import { useSelector } from 'react-redux'; import { getMemoizedMetadataContractName } from '../selectors'; import { useName } from './useName'; +import { useFirstPartyContractName } from './useFirstPartyContractName'; /** * Attempts to resolve the name for the given parameters. @@ -19,14 +20,16 @@ export function useDisplayName( variation?: string, ): { name: string | null; hasPetname: boolean } { const nameEntry = useName(value, type, variation); + const firstPartyContractName = useFirstPartyContractName( + value, + type, + variation, + ); const contractName = useSelector((state) => (getMemoizedMetadataContractName as any)(state, value), ); - if (nameEntry?.name) { - return { name: nameEntry.name, hasPetname: true }; - } - if (contractName) { - return { name: contractName, hasPetname: false }; - } - return { name: null, hasPetname: false }; + return { + name: nameEntry?.name || firstPartyContractName || contractName || null, + hasPetname: Boolean(nameEntry?.name), + }; } diff --git a/ui/hooks/useFirstPartyContractName.test.ts b/ui/hooks/useFirstPartyContractName.test.ts new file mode 100644 index 000000000000..05979755f06a --- /dev/null +++ b/ui/hooks/useFirstPartyContractName.test.ts @@ -0,0 +1,76 @@ +import { NameType } from '@metamask/name-controller'; +import { getCurrentChainId } from '../selectors'; +import { CHAIN_IDS } from '../../shared/constants/network'; +import { useFirstPartyContractName } from './useFirstPartyContractName'; + +jest.mock('react-redux', () => ({ + useSelector: (selector: any) => selector(), +})); + +jest.mock('../selectors', () => ({ + getCurrentChainId: jest.fn(), + getNames: jest.fn(), +})); + +const BRIDGE_NAME_MOCK = 'MetaMask Bridge'; +const BRIDGE_MAINNET_ADDRESS_MOCK = + '0x0439e60F02a8900a951603950d8D4527f400C3f1'; +const BRIDGE_OPTIMISM_ADDRESS_MOCK = + '0xB90357f2b86dbfD59c3502215d4060f71DF8ca0e'; +const UNKNOWN_ADDRESS_MOCK = '0xabc123'; + +describe('useFirstPartyContractName', () => { + const getCurrentChainIdMock = jest.mocked(getCurrentChainId); + beforeEach(() => { + jest.resetAllMocks(); + + getCurrentChainIdMock.mockReturnValue(CHAIN_IDS.MAINNET); + }); + + it('returns null if no name found', () => { + const name = useFirstPartyContractName( + UNKNOWN_ADDRESS_MOCK, + NameType.ETHEREUM_ADDRESS, + ); + + expect(name).toBe(null); + }); + + it('returns name if found', () => { + const name = useFirstPartyContractName( + BRIDGE_MAINNET_ADDRESS_MOCK, + NameType.ETHEREUM_ADDRESS, + ); + expect(name).toBe(BRIDGE_NAME_MOCK); + }); + + it('uses variation if specified', () => { + const name = useFirstPartyContractName( + BRIDGE_OPTIMISM_ADDRESS_MOCK, + NameType.ETHEREUM_ADDRESS, + CHAIN_IDS.OPTIMISM, + ); + + expect(name).toBe(BRIDGE_NAME_MOCK); + }); + + it('returns null if type is not address', () => { + const alternateType = 'alternateType' as NameType; + + const name = useFirstPartyContractName( + BRIDGE_MAINNET_ADDRESS_MOCK, + alternateType, + ); + + expect(name).toBe(null); + }); + + it('normalizes addresses to lowercase', () => { + const name = useFirstPartyContractName( + BRIDGE_MAINNET_ADDRESS_MOCK.toUpperCase(), + NameType.ETHEREUM_ADDRESS, + ); + + expect(name).toBe(BRIDGE_NAME_MOCK); + }); +}); diff --git a/ui/hooks/useFirstPartyContractName.ts b/ui/hooks/useFirstPartyContractName.ts new file mode 100644 index 000000000000..2e70cedcf73f --- /dev/null +++ b/ui/hooks/useFirstPartyContractName.ts @@ -0,0 +1,25 @@ +import { NameType } from '@metamask/name-controller'; +import { useSelector } from 'react-redux'; +import { getCurrentChainId } from '../selectors'; +import { FIRST_PARTY_CONTRACT_NAMES } from '../../shared/constants/first-party-contracts'; + +export function useFirstPartyContractName( + value: string, + type: NameType, + variation?: string, +): string | null { + if (type !== NameType.ETHEREUM_ADDRESS) { + return null; + } + const currentChainId = useSelector(getCurrentChainId); + const chainId = variation ?? currentChainId; + const normalizedValue = value.toLowerCase(); + + return ( + Object.keys(FIRST_PARTY_CONTRACT_NAMES).find( + (name) => + FIRST_PARTY_CONTRACT_NAMES[name]?.[chainId]?.toLowerCase() === + normalizedValue, + ) ?? null + ); +} From 3e47921decd88db4b224bd485cc43fbe41dd2681 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 27 Feb 2024 07:59:40 -0330 Subject: [PATCH 10/55] Capture error in migration 105 if selectedAddress is not a string (#23194) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We are seeing an error in prod that could only be explained if a migration fails. This PR adds some error handling to better detect and monitor one possible source of migration failure. The prod error is: > TypeError getSelectedInternalAccount(ui/selectors/selectors.js) > Cannot read properties of undefined (reading 'selectedAccount') https://metamask.sentry.io/issues/4999905586/?project=273505&query=is%3Aunresolved+release%3A11.10.0+is%3Anew&referrer=issue-stream&statsPeriod=7d&stream_index=9 ## **Manual testing steps** Unit tests should pass. Also: 1. Build this branch and install metamask 2. During the onboarding flow, make sure to opt _in_ to metametrics 3. Run the following script in the background console ``` chrome.storage.local.get(({ data, meta }) => chrome.storage.local.set({ data: { ...data, PreferencesController: {selectedAddress: undefined} }, meta: {...meta, version: 104} }, () => { window.location.reload() })) ``` You should see a network request to sentry with `state.PreferencesController?.selectedAddress is undefined` in the payload ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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/migrations/105.test.ts | 28 ++++++++++++++++++++++++++++ app/scripts/migrations/105.ts | 8 ++++++++ 2 files changed, 36 insertions(+) diff --git a/app/scripts/migrations/105.test.ts b/app/scripts/migrations/105.test.ts index 1690d67773e6..5349918cbdba 100644 --- a/app/scripts/migrations/105.test.ts +++ b/app/scripts/migrations/105.test.ts @@ -6,6 +6,15 @@ import { migrate } from './105'; const MOCK_ADDRESS = '0x0'; const MOCK_ADDRESS_2 = '0x1'; +const sentryCaptureExceptionMock = jest.fn(); + +global.sentry = { + startSession: jest.fn(), + endSession: jest.fn(), + toggleSession: jest.fn(), + captureException: sentryCaptureExceptionMock, +}; + function addressToUUID(address: string): string { return uuid({ random: sha256FromString(address).slice(0, 16), @@ -257,5 +266,24 @@ describe('migration #105', () => { }, }); }); + + it('captures an exception if the selectedAddress state is invalid', async () => { + const oldData = { + PreferencesController: { + identities: {}, + selectedAddress: undefined, + }, + }; + const oldStorage = { + meta: { version: 103 }, + data: oldData, + }; + await migrate(oldStorage); + + expect(sentryCaptureExceptionMock).toHaveBeenCalledTimes(1); + expect(sentryCaptureExceptionMock).toHaveBeenCalledWith( + new Error(`state.PreferencesController?.selectedAddress is undefined`), + ); + }); }); }); diff --git a/app/scripts/migrations/105.ts b/app/scripts/migrations/105.ts index 38097d7e20e6..4ad6ae296838 100644 --- a/app/scripts/migrations/105.ts +++ b/app/scripts/migrations/105.ts @@ -102,6 +102,14 @@ function createSelectedAccountForAccountsController( ) { const selectedAddress = state.PreferencesController?.selectedAddress; + if (typeof selectedAddress !== 'string') { + global.sentry?.captureException?.( + new Error( + `state.PreferencesController?.selectedAddress is ${selectedAddress}`, + ), + ); + } + const selectedAccount = Object.values( state.AccountsController.internalAccounts.accounts, ).find((account: InternalAccount) => { From 77c680813da1625a62684702ed5c0ff71ffc214a Mon Sep 17 00:00:00 2001 From: Brian Bergeron Date: Fri, 23 Feb 2024 06:41:34 -0800 Subject: [PATCH 11/55] fix: missing network images (#23140) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Fixes an issue where the image files for some networks were not present in the filesystem, causing metamask to crash when trying to load them. The affected chains were: ``` 0x288 ./images/endurance-smart-chain.png 0x4d2 ./images/setp.svg 0x6a ./images/velas.svg 0x133e40 ./images/zkatana.svg ``` [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23140?quickstart=1) ## **Related issues** Fixes: https://github.com/MetaMask/metamask-extension/issues/23084 ## **Manual testing steps** Add any of the 4 affected chains to metamask, and visit the settings -> networks page. should not crash. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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/images/velas.svg | 1 + shared/constants/network.test.ts | 11 +++++++++++ shared/constants/network.ts | 6 +++--- 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 app/images/velas.svg create mode 100644 shared/constants/network.test.ts diff --git a/app/images/velas.svg b/app/images/velas.svg new file mode 100644 index 000000000000..910ad1cb58cf --- /dev/null +++ b/app/images/velas.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/shared/constants/network.test.ts b/shared/constants/network.test.ts new file mode 100644 index 000000000000..dfcf313314aa --- /dev/null +++ b/shared/constants/network.test.ts @@ -0,0 +1,11 @@ +import { existsSync } from 'fs'; +import { join } from 'path'; +import { CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP } from './network'; + +describe('NetworkConstants', () => { + it('has images files that exist for defined networks', () => { + Object.values(CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP).forEach((image) => + expect(existsSync(join('app', image))).toBe(true), + ); + }); +}); diff --git a/shared/constants/network.ts b/shared/constants/network.ts index 0475589107f5..aa6a20fcf3ad 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -373,7 +373,7 @@ export const DEXALOT_SUBNET_IMAGE_URL = './images/dexalut-subnet.svg'; export const DFK_CHAIN_IMAGE_URL = './images/dfk.png'; export const DOGECHAIN_IMAGE_URL = './images/dogechain.jpeg'; export const ENDURANCE_SMART_CHAIN_MAINNET_IMAGE_URL = - './images/endurance-smart-chain.png'; + './images/endurance-smart-chain-mainnet.png'; export const ETHEREUM_CLASSIC_MAINNET_IMAGE_URL = './images/eth_classic.svg'; export const EVMOS_IMAGE_URL = './images/evmos.svg'; export const FLARE_MAINNET_IMAGE_URL = './images/flare-mainnet.svg'; @@ -398,11 +398,11 @@ export const SHARDEUM_LIBERTY_2X_IMAGE_URL = './images/shardeum-2.svg'; export const SHARDEUM_SPHINX_1X_IMAGE_URL = './images/shardeum-1.svg'; export const SHIB_MAINNET_IMAGE_URL = './images/shiba.svg'; export const SONGBIRD_MAINNET_IMAGE_URL = './images/songbird.svg'; -export const STEP_NETWORK_IMAGE_URL = './images/setp.svg'; +export const STEP_NETWORK_IMAGE_URL = './images/step.svg'; export const TELOS_EVM_MAINNET_IMAGE_URL = './images/telos.svg'; export const TENET_MAINNET_IMAGE_URL = './images/tenet.svg'; export const VELAS_EVM_MAINNET_IMAGE_URL = './images/velas.svg'; -export const ZKATANA_MAINNET_IMAGE_URL = './images/zkatana.svg'; +export const ZKATANA_MAINNET_IMAGE_URL = './images/zkatana.png'; export const ZORA_MAINNET_IMAGE_URL = './images/zora.svg'; export const INFURA_PROVIDER_TYPES = [ From 4544fadf053b1818ed7c085ec3c81ea1fcb39d00 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 27 Feb 2024 08:03:00 -0330 Subject: [PATCH 12/55] v11.10.1 --- CHANGELOG.md | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18db909ce3ad..9bced2560161 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.10.1] +### Fixed +- Fix custom network editing, via Settings, for some networks ([#23140](https://github.com/MetaMask/metamask-extension/pull/23140)) + ## [11.10.0] ### Added - Added preset network image avatars in the 'Select a network' pop-up ([#22643](https://github.com/MetaMask/metamask-extension/pull/22643)) @@ -4389,7 +4393,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.1...HEAD +[11.10.1]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.10.1 [11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 [11.9.5]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...v11.9.5 [11.9.4]: https://github.com/MetaMask/metamask-extension/compare/v11.9.3...v11.9.4 diff --git a/package.json b/package.json index 2c751ab3ed8d..c9464b8872b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.10.0", + "version": "11.10.1", "private": true, "repository": { "type": "git", From 99cdf016e92ff25b49ed2bef3275428f7d6410d0 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Wed, 21 Feb 2024 23:29:45 +0100 Subject: [PATCH 13/55] test: disable ppom e2e tests temporarily (#23103) Disable ppom tests until cdn responses are mocked. This unblocks ci. --- .../e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js | 3 ++- .../e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js | 3 ++- test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js | 9 ++++++--- .../ppom-blockaid-alert-trade-order-farming.spec.js | 3 ++- .../ppom-blockaid-setApprovalForAll-farming.spec.js | 3 ++- test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js | 3 ++- test/e2e/tests/ppom-toggle-settings.spec.js | 6 ++++-- 7 files changed, 20 insertions(+), 10 deletions(-) diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js index 6afd95478ef1..a014ae0ff7dd 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js @@ -210,7 +210,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Malicious ERC20 Approval @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js index 3777c83af37f..559d33790269 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js @@ -161,7 +161,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Malicious ERC20 Transfer @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js index 161e15e88aa6..f388bd6c1942 100644 --- a/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-simple-send.spec.js @@ -129,7 +129,8 @@ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { if (process.env.MULTICHAIN) { return; } - it('should not show security alerts for benign requests', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should not show security alerts for benign requests', async function () { await withFixtures( { dapp: true, @@ -161,7 +162,8 @@ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { * 'malicious_domain'. Some other tests are found in other files: * e.g. test/e2e/flask/ppom-blockaid-alert-.spec.js */ - it('should show security alerts for malicious requests', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show security alerts for malicious requests', async function () { await withFixtures( { dapp: true, @@ -204,7 +206,8 @@ describe('Simple Send Security Alert - Blockaid @no-mmi', function () { ); }); - it('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js b/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js index 5ac58bf7a1b8..82bbbf4d3f3a 100644 --- a/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-trade-order-farming.spec.js @@ -90,7 +90,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Set Trade farming order @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js index 1b2ca4587ae9..f072e8502c91 100644 --- a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js +++ b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js @@ -248,7 +248,8 @@ async function mockInfura(mockServer) { } describe('PPOM Blockaid Alert - Set Approval to All @no-mmi', function () { - it('should show banner alert', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show banner alert', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js b/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js index 25e98c67767a..9c4b7335b2d2 100644 --- a/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js +++ b/test/e2e/tests/ppom-blockaid-toggle-metrics.spec.js @@ -52,7 +52,8 @@ async function mockServerCalls(mockServer) { } describe('PPOM Blockaid Alert - Metrics @no-mmi', function () { - it('Successfully track button toggle on/off', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('Successfully track button toggle on/off', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-toggle-settings.spec.js b/test/e2e/tests/ppom-toggle-settings.spec.js index b6343a38a969..b2b79e49d354 100644 --- a/test/e2e/tests/ppom-toggle-settings.spec.js +++ b/test/e2e/tests/ppom-toggle-settings.spec.js @@ -9,7 +9,8 @@ const { const FixtureBuilder = require('../fixture-builder'); describe('PPOM Settings @no-mmi', function () { - it('should not show the PPOM warning when toggle is off', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should not show the PPOM warning when toggle is off', async function () { await withFixtures( { dapp: true, @@ -47,7 +48,8 @@ describe('PPOM Settings @no-mmi', function () { ); }); - it('should show the PPOM warning when the toggle is on', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show the PPOM warning when the toggle is on', async function () { await withFixtures( { dapp: true, From 2a6b12f8871c0b73887b5b12e1a17e6e006232cc Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Fri, 23 Feb 2024 21:07:28 +0900 Subject: [PATCH 14/55] fix(deps): socks@2.8.0->2.8.1 (#23143) --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 575dd3470091..e22d53d4fb75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31606,12 +31606,12 @@ __metadata: linkType: hard "socks@npm:^2.6.1, socks@npm:^2.6.2, socks@npm:^2.7.1": - version: 2.8.0 - resolution: "socks@npm:2.8.0" + version: 2.8.1 + resolution: "socks@npm:2.8.1" dependencies: ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: ed0224ce2c7daaa7690cb87cf53d9703ffc4e983aca221f6f5b46767b232658df49494fd86acd0bf97ada6de05248ea8ea625c2343d48155d8463fc40d4a340f + checksum: a3cc38e0716ab53a2db3fa00c703ca682ad54dbbc9ed4c7461624a999be6fa7cdc79fc904c411618e698d5eff55a55aa6d9329169a7db11636d0200814a2b5aa languageName: node linkType: hard From 3a9f95f4682d83eaf3bed5929b6827b637f48909 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Tue, 27 Feb 2024 15:31:18 +0100 Subject: [PATCH 15/55] fix: cherry-pick bug fix to RC (#23200) ## **Description** Cherry-picks https://github.com/MetaMask/metamask-extension/pull/22915 to the RC. --- .../permission-page-container.component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/permission-page-container/permission-page-container.component.js b/ui/components/app/permission-page-container/permission-page-container.component.js index 37118bc5e6ed..15745a330b81 100644 --- a/ui/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/components/app/permission-page-container/permission-page-container.component.js @@ -57,7 +57,7 @@ export default class PermissionPageContainer extends Component { state = {}; getRequestedPermissions() { - return Object.entries(this.props.request.permissions).reduce( + return Object.entries(this.props.request.permissions ?? {}).reduce( (acc, [permissionName, permissionValue]) => { ///: BEGIN:ONLY_INCLUDE_IF(snaps) if (permissionName === RestrictedMethods.wallet_snap) { From 8f5af660199a881776b125819285be2473afc473 Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:58:48 +0100 Subject: [PATCH 16/55] gtest: fix several ppom testcases due to description change (#23052) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems that the description response for the malicious mocked requests has changed in a recent update. This PR aims to fix the e2e tests. This also reveals the strong need for using a stable version of the cdn, by: - Either using the cdn test version of ppom (stable), like we used to do --> that was changed due to some issue Blockaid had on their end - Or mocking the cdn responses and keep them always the same --> to investigate if this is doable, since the responses that we get are in a "weird format" (see example below) ![Screenshot from 2024-02-19 19-23-25](https://github.com/MetaMask/metamask-extension/assets/54408225/54589804-2c9f-40c7-8f67-2ff800f0b0be) Another scenario to explore for some of these specs, would be to see if we can inject the files directly in the ppomDB. In the same way we initialize the wallet with a certain state, we could initialize the wallet with the ppomDB prefilled in storage. This PR however, aims to unblock ci in the fastes possible way Fixes: https://github.com/MetaMask/metamask-extension/issues/23053 1. Check ci or run them locally ![Screenshot from 2024-02-19 19-04-44](https://github.com/MetaMask/metamask-extension/assets/54408225/248ae58c-fb40-4531-8028-a3e218ed44b3) - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [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. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] 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/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js | 2 +- test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js | 2 +- test/e2e/tests/ppom-blockaid-alert.spec.js | 3 ++- test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js index a014ae0ff7dd..aed08415da79 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-approval.spec.js @@ -233,7 +233,7 @@ describe('PPOM Blockaid Alert - Malicious ERC20 Approval @no-mmi', function () { const expectedTitle = 'This is a deceptive request'; const expectedDescription = - 'If you approve this request, a third party known for scams might take all your assets.'; + 'If you approve this request, you might lose your assets.'; // Click TestDapp button to send JSON-RPC request await driver.clickElement('#maliciousApprovalButton'); diff --git a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js index 559d33790269..5b42a2c2de38 100644 --- a/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert-erc20-transfer.spec.js @@ -181,7 +181,7 @@ describe('PPOM Blockaid Alert - Malicious ERC20 Transfer @no-mmi', function () { async ({ driver }) => { const expectedTitle = 'This is a deceptive request'; const expectedDescription = - 'If you approve this request, a third party known for scams will take all your assets.'; + 'If you approve this request, you might lose your assets.'; await unlockWallet(driver); await openDapp(driver); diff --git a/test/e2e/tests/ppom-blockaid-alert.spec.js b/test/e2e/tests/ppom-blockaid-alert.spec.js index 978d6bea57ab..37a06d44050d 100644 --- a/test/e2e/tests/ppom-blockaid-alert.spec.js +++ b/test/e2e/tests/ppom-blockaid-alert.spec.js @@ -287,7 +287,8 @@ describe('Confirmation Security Alert - Blockaid @no-mmi', function () { ); }); - it('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should show "Request may not be safe" if the PPOM request fails to check transaction', async function () { await withFixtures( { dapp: true, diff --git a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js index f072e8502c91..94ef3f4a64a5 100644 --- a/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js +++ b/test/e2e/tests/ppom-blockaid-setApprovalForAll-farming.spec.js @@ -271,7 +271,7 @@ describe('PPOM Blockaid Alert - Set Approval to All @no-mmi', function () { const expectedTitle = 'This is a deceptive request'; const expectedDescription = - 'If you approve this request, a third party known for scams might take all your assets.'; + 'If you approve this request, you might lose your assets.'; // Click TestDapp button to send JSON-RPC request await driver.clickElement('#maliciousSetApprovalForAll'); From a482941e73da2f9feb8d5e190c4214f1238f6223 Mon Sep 17 00:00:00 2001 From: chloeYue <105063779+chloeYue@users.noreply.github.com> Date: Wed, 28 Feb 2024 10:07:24 +0100 Subject: [PATCH 17/55] V11.11.0 changelog (#23112) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** V11.11.0 changelog ## **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 Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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 --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cb59405992b..eab79dd0362e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [11.11.0] +### Added +- Added 'Pet Names' feature, allowing users to see preferred or suggested nicknames in the places of addesses + - Added 'What's New' popup for Petnames feature ([#22780](https://github.com/MetaMask/metamask-extension/pull/22780)) + - Introduced toggle for Petnames in experimental settings ([#22456](https://github.com/MetaMask/metamask-extension/pull/22456)) + - UI enhancements for initial petnames release, including new "Recognized" category and visual refinements ([#22772](https://github.com/MetaMask/metamask-extension/pull/22772)) + - Enhanced token name display with pet names ([#22734](https://github.com/MetaMask/metamask-extension/pull/22734)) +- Added title to Personal Sign component in confirmation design ([#22749](https://github.com/MetaMask/metamask-extension/pull/22749)) +- Added progress indicator for scanning QR codes with hardware wallets ([#20947](https://github.com/MetaMask/metamask-extension/pull/20947)) + +### Changed +- Moved security alerts from Experimental to Security & Privacy settings ([#22813](https://github.com/MetaMask/metamask-extension/pull/22813)) +- Updated BlockaidBannerAlert to support false positive reporting for failed types ([#22742](https://github.com/MetaMask/metamask-extension/pull/22742)) +- Enhanced BlockaidBannerAlert functionality and display ([#22625](https://github.com/MetaMask/metamask-extension/pull/22625)) +- Disabled smart swaps for Snap accounts ([#22731](https://github.com/MetaMask/metamask-extension/pull/22731)) +- Disabled MetaMask on Battle.net to fix a 2FA login issue ([#20396](https://github.com/MetaMask/metamask-extension/pull/20396)) +- Revised warning copy for mismatched chainID and currency symbol when adding custom networks ([#22648](https://github.com/MetaMask/metamask-extension/pull/22648)) +- Improved UX to display multiple custom networks with the same ID but different RPC URLs in network selection ([#22693](https://github.com/MetaMask/metamask-extension/pull/22693)) +- Updated the connections icon to display the connected dapp icon ([#22634](https://github.com/MetaMask/metamask-extension/pull/22634)) +- Added title to Personal Sign page ([#22749](https://github.com/MetaMask/metamask-extension/pull/22749)) +- Update padding in accounts details modal ([#22775](https://github.com/MetaMask/metamask-extension/pull/22775)) +- [MMI] Refactored display of custodian deep link to improve efficiency and fix potential race conditions ([#22825](https://github.com/MetaMask/metamask-extension/pull/22825)) +- [MMI] Hid the new buy & receive button under MMI build for a cleaner interface ([#22384](https://github.com/MetaMask/metamask-extension/pull/22384)) + +### Fixed +- Fixed cancel transaction signing from activity list ([#22676](https://github.com/MetaMask/metamask-extension/pull/22676)) +- Fixed incorrect account name display in account details and receive list ([#22844](https://github.com/MetaMask/metamask-extension/pull/22844)) +- Fixed IPFS NFTs fetching issue for manually imported NFTs ([#22627](https://github.com/MetaMask/metamask-extension/pull/22627)) +- Fixed "send max" ETH calculation issue to adjust for gas changes ([#22694](https://github.com/MetaMask/metamask-extension/pull/22694)) +- Fixed sign button color and updated deprecated components in SignatureRequestOriginalWarning for visual consistency ([#22741](https://github.com/MetaMask/metamask-extension/pull/22741)) + ## [11.10.0] ### Added - Added preset network image avatars in the 'Select a network' pop-up ([#22643](https://github.com/MetaMask/metamask-extension/pull/22643)) @@ -4391,8 +4421,7 @@ 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/v11.11.0...HEAD -[11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.8.0...v11.11.0 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...HEAD +[11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.11.0 [11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 [11.9.5]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...v11.9.5 [11.9.4]: https://github.com/MetaMask/metamask-extension/compare/v11.9.3...v11.9.4 From 5ad0a4d6809d3d196a5acaaceb52c983d08436a4 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 4 Mar 2024 14:58:19 -0330 Subject: [PATCH 18/55] v11.11.1 --- CHANGELOG.md | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6618f4aaa525..fdaf4f59cc7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.11.1] +### Added +- Adds a staking button to the mainnet Ethereum token list item ([#22347](https://github.com/MetaMask/metamask-extension/pull/22347)) + ## [11.11.0] ### Added - Added 'Pet Names' feature, allowing users to see preferred or suggested nicknames in the places of addesses @@ -4424,7 +4428,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...HEAD +[11.11.1]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...v11.11.1 [11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.1...v11.11.0 [11.10.1]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.10.1 [11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 diff --git a/package.json b/package.json index bcbbd956dba0..dfcae21af58d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.11.0", + "version": "11.11.1", "private": true, "repository": { "type": "git", From 6cf51ce1ed1c2451674bfc60e39b55b0b5af54d5 Mon Sep 17 00:00:00 2001 From: martahj Date: Thu, 15 Feb 2024 12:37:49 -0600 Subject: [PATCH 19/55] Revert remove staking link (#22816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts the commits to remove the "Stake" button and associated announcement, ie the changes in [this PR](https://github.com/MetaMask/metamask-extension/pull/22669). Original PR: https://github.com/MetaMask/metamask-extension/pull/22347 1. Go to Token Listing 2. Verify that the new staking icon shows only for ETH mainnet 3. Click on button; it should go to the [MetaMask Porfolio stake page](https://portfolio.metamask.io/stake) 4. Verify that onClick, a new metametrics event is tracked Original PR: https://github.com/MetaMask/metamask-extension/pull/22291 1. Install MM build with this change 2. The Stake announcement should appear, either last on the "What's New" list if you haven't seen previous announcements or as the only item in "What's New" if you have 5. CTA should not click through to anything (just close the notification) Screenshot 2024-02-05 at 11 00 17 AM Screenshot 2024-02-05 at 10 56 29 AM Screenshot 2024-02-05 at 10 53 22 AM - [X] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [X] I've clearly explained what problem this PR is solving and how it is solved. - [X] I've linked related issues - [X] I've included manual testing steps - [X] I've included screenshots/recordings if applicable - [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. - [x] I’ve properly set the pull request status: - [x] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [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. --- app/_locales/en/messages.json | 12 +++ app/images/icons/stake.svg | 3 + ...ortfolio-stake-notification-light-mode.png | Bin 0 -> 18898 bytes shared/constants/metametrics.ts | 1 + shared/notifications/index.js | 22 +++++- test/e2e/tests/add-hide-token.spec.js | 2 +- test/e2e/tests/add-multiple-tokens.spec.js | 2 +- ui/components/app/asset-list/asset-list.js | 9 +++ .../__snapshots__/token-cell.test.js.snap | 2 +- .../app/whats-new-popup/whats-new-popup.js | 5 ++ .../token-list-item.test.js.snap | 2 +- .../token-list-item/token-list-item.js | 74 ++++++++++++++++-- .../token-list-item.stories.js | 3 + .../token-list-item/token-list-item.test.js | 32 +++++++- ui/selectors/selectors.js | 2 + 15 files changed, 160 insertions(+), 11 deletions(-) create mode 100644 app/images/icons/stake.svg create mode 100644 app/images/portfolio-stake-notification-light-mode.png diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 3af1c1b4e964..a0a20eed26b0 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3177,6 +3177,18 @@ "notificationsPetnamesTitle": { "message": "Suggested nicknames are here!" }, + "notificationsStakingPortfolioActionText": { + "message": "Got it", + "description": "Action text for a notification in the 'See What's New' popup. Tells users that staking is now available in the portfolio app." + }, + "notificationsStakingPortfolioDescription": { + "message": "Now you can stake ETH and manage your rewards all in one place.", + "description": "Description for a notification in the 'See What's New' popup. Tells users that staking is now available in the portfolio app." + }, + "notificationsStakingPortfolioTitle": { + "message": "Stake smarter in Portfolio", + "description": "Title for a notification in the 'See What's New' popup. Tells users that staking is now available in the portfolio app." + }, "notificationsU2FLedgerLiveDescription": { "message": "U2F and Ledger Live are no longer available on Chrome. You can still connect Ledger devices on Chrome using Webhid.", "description": "Description of a notification in the 'See What's New' popup. Describes the U2F and Ledger Live connection modes are now deprecated" diff --git a/app/images/icons/stake.svg b/app/images/icons/stake.svg new file mode 100644 index 000000000000..54c6762e3cab --- /dev/null +++ b/app/images/icons/stake.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/images/portfolio-stake-notification-light-mode.png b/app/images/portfolio-stake-notification-light-mode.png new file mode 100644 index 0000000000000000000000000000000000000000..33cbe293392000d65b8efc208d0264b56ec3fd53 GIT binary patch literal 18898 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 literal 0 HcmV?d00001 diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 3db2c67f6785..f5d556be3f03 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -595,6 +595,7 @@ export enum MetaMetricsEventName { SrpViewSrpText = 'Views SRP', SrpCopiedToClipboard = 'Copies SRP to clipboard', SrpToConfirmBackup = 'SRP Backup Confirm Displayed', + StakingEntryPointClicked = 'Stake Button Clicked', SupportLinkClicked = 'Support Link Clicked', TermsOfUseShown = 'Terms of Use Shown', TermsOfUseAccepted = 'Terms of Use Accepted', diff --git a/shared/notifications/index.js b/shared/notifications/index.js index 57b2e0892a54..7e57c92ba9c0 100644 --- a/shared/notifications/index.js +++ b/shared/notifications/index.js @@ -9,7 +9,8 @@ export const NOTIFICATION_OPEN_BETA_SNAPS = 26; export const NOTIFICATION_BUY_SELL_BUTTON = 27; export const NOTIFICATION_U2F_LEDGER_LIVE = 28; export const NOTIFICATION_BLOCKAID_DEFAULT = 29; -export const NOTIFICATION_PETNAMES = 30; +export const NOTIFICATION_STAKING_PORTFOLIO = 30; +export const NOTIFICATION_PETNAMES = 31; export const UI_NOTIFICATIONS = { 1: { @@ -178,6 +179,14 @@ export const UI_NOTIFICATIONS = { date: null, }, ///: END:ONLY_INCLUDE_IF + [NOTIFICATION_STAKING_PORTFOLIO]: { + id: Number(NOTIFICATION_STAKING_PORTFOLIO), + date: null, + image: { + src: 'images/portfolio-stake-notification-light-mode.png', + width: '100%', + }, + }, [NOTIFICATION_PETNAMES]: { id: Number(NOTIFICATION_PETNAMES), date: null, @@ -477,6 +486,17 @@ export const getTranslatedUINotifications = ( ) : '', }, + [NOTIFICATION_STAKING_PORTFOLIO]: { + ...UI_NOTIFICATIONS[NOTIFICATION_STAKING_PORTFOLIO], + title: t('notificationsStakingPortfolioTitle'), + description: [t('notificationsStakingPortfolioDescription')], + actionText: t('notificationsStakingPortfolioActionText'), + date: UI_NOTIFICATIONS[NOTIFICATION_STAKING_PORTFOLIO].date + ? new Intl.DateTimeFormat(formattedLocale).format( + new Date(UI_NOTIFICATIONS[NOTIFICATION_STAKING_PORTFOLIO].date), + ) + : '', + }, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) [NOTIFICATION_BLOCKAID_DEFAULT]: { ...UI_NOTIFICATIONS[NOTIFICATION_BLOCKAID_DEFAULT], diff --git a/test/e2e/tests/add-hide-token.spec.js b/test/e2e/tests/add-hide-token.spec.js index 9b2e184ff00b..e86b5d1c870e 100644 --- a/test/e2e/tests/add-hide-token.spec.js +++ b/test/e2e/tests/add-hide-token.spec.js @@ -54,7 +54,7 @@ describe('Add hide token', function () { await driver.clickElement({ text: 'Tokens', tag: 'button' }); - await driver.clickElement({ text: 'TST', tag: 'p' }); + await driver.clickElement({ text: 'TST', tag: 'span' }); await driver.clickElement('[data-testid="asset-options__button"]'); diff --git a/test/e2e/tests/add-multiple-tokens.spec.js b/test/e2e/tests/add-multiple-tokens.spec.js index a1da4eac1708..d6d9200fe464 100644 --- a/test/e2e/tests/add-multiple-tokens.spec.js +++ b/test/e2e/tests/add-multiple-tokens.spec.js @@ -99,7 +99,7 @@ describe('Multiple ERC20 Watch Asset', function () { // Check all three tokens have been added to the token list. const addedTokens = await driver.findElements({ - tag: 'p', + tag: 'span', text: 'TST', }); assert.equal(addedTokens.length, 3); diff --git a/ui/components/app/asset-list/asset-list.js b/ui/components/app/asset-list/asset-list.js index 9696f7eb51e1..0c3a1a141ff0 100644 --- a/ui/components/app/asset-list/asset-list.js +++ b/ui/components/app/asset-list/asset-list.js @@ -18,6 +18,7 @@ import { ///: END:ONLY_INCLUDE_IF getSelectedAccount, getPreferences, + getIsMainnet, } from '../../../selectors'; import { getNativeCurrency, @@ -62,6 +63,7 @@ const AssetList = ({ onClickAsset }) => { const nativeCurrency = useSelector(getNativeCurrency); const showFiat = useSelector(getShouldShowFiat); const chainId = useSelector(getCurrentChainId); + const isMainnet = useSelector(getIsMainnet); const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const { ticker, type } = useSelector(getProviderConfig); const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol( @@ -123,6 +125,12 @@ const AssetList = ({ onClickAsset }) => { const defaultSwapsToken = useSelector(getSwapsDefaultToken); ///: END:ONLY_INCLUDE_IF + let isStakeable = isMainnet; + + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + isStakeable = false; + ///: END:ONLY_INCLUDE_IF + return ( <> {detectedTokens.length > 0 && @@ -211,6 +219,7 @@ const AssetList = ({ onClickAsset }) => { tokenImage={balanceIsLoading ? null : primaryTokenImage} isOriginalTokenSymbol={isOriginalNativeSymbol} isNativeCurrency + isStakeable={isStakeable} />
{ updateViewedNotifications({ [NOTIFICATION_U2F_LEDGER_LIVE]: true }); }, + [NOTIFICATION_STAKING_PORTFOLIO]: () => { + updateViewedNotifications({ [NOTIFICATION_STAKING_PORTFOLIO]: true }); + }, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) [NOTIFICATION_BLOCKAID_DEFAULT]: () => { updateViewedNotifications({ [NOTIFICATION_BLOCKAID_DEFAULT]: true }); @@ -371,6 +375,7 @@ export default function WhatsNewPopup({ onClose }) { [NOTIFICATION_OPEN_BETA_SNAPS]: renderFirstNotification, [NOTIFICATION_BUY_SELL_BUTTON]: renderFirstNotification, [NOTIFICATION_U2F_LEDGER_LIVE]: renderFirstNotification, + [NOTIFICATION_STAKING_PORTFOLIO]: renderFirstNotification, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) [NOTIFICATION_BLOCKAID_DEFAULT]: renderFirstNotification, ///: END:ONLY_INCLUDE_IF diff --git a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap index 2d5fa9de4841..c64a5372e1a9 100644 --- a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap +++ b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap @@ -41,7 +41,7 @@ exports[`TokenListItem should render correctly 1`] = ` class="mm-box mm-box--display-flex mm-box--gap-1 mm-box--flex-direction-row mm-box--justify-content-space-between" >
{ const t = useI18nContext(); const primaryTokenImage = useSelector(getNativeCurrencyImage); const trackEvent = useContext(MetaMetricsContext); + const metaMetricsId = useSelector(getMetaMetricsId); const chainId = useSelector(getCurrentChainId); // Scam warning @@ -82,7 +88,45 @@ export const TokenListItem = ({ title === CURRENCY_SYMBOLS.ETH && isOriginalTokenSymbol ? t('networkNameEthereum') : title; - + const stakeableTitle = ( + { + e.preventDefault(); + e.stopPropagation(); + const url = getPortfolioUrl('stake', 'ext_stake_button', metaMetricsId); + global.platform.openTab({ url }); + trackEvent({ + event: MetaMetricsEventName.StakingEntryPointClicked, + category: MetaMetricsEventCategory.Tokens, + properties: { + location: 'Token List Item', + text: 'Stake', + chain_id: chainId, + token_symbol: tokenSymbol, + }, + }); + }} + > + + + {t('stake')} + + + + ); // Used for badge icon const currentNetwork = useSelector(getCurrentNetwork); const testNetworkBackgroundColor = useSelector(getTestNetworkBackgroundColor); @@ -160,7 +204,10 @@ export const TokenListItem = ({ justifyContent={JustifyContent.spaceBetween} gap={1} > - + {title?.length > 12 ? ( - {tokenSymbol} + {isStakeable ? ( + <> + {tokenSymbol} {stakeableTitle} + + ) : ( + tokenSymbol + )} ) : ( @@ -184,7 +237,13 @@ export const TokenListItem = ({ variant={TextVariant.bodyMd} ellipsis > - {tokenSymbol} + {isStakeable ? ( + + {tokenSymbol} {stakeableTitle} + + ) : ( + tokenSymbol + )} )} @@ -205,9 +264,10 @@ export const TokenListItem = ({ {secondary} @@ -317,4 +377,8 @@ TokenListItem.propTypes = { * isNativeCurrency represents if this item is the native currency */ isNativeCurrency: PropTypes.bool, + /** + * isStakeable represents if this item is stakeable + */ + isStakeable: PropTypes.bool, }; diff --git a/ui/components/multichain/token-list-item/token-list-item.stories.js b/ui/components/multichain/token-list-item/token-list-item.stories.js index 0cf57ae7defc..473fd6e2affb 100644 --- a/ui/components/multichain/token-list-item/token-list-item.stories.js +++ b/ui/components/multichain/token-list-item/token-list-item.stories.js @@ -64,6 +64,9 @@ DefaultStory.decorators = [ ), ]; +DefaultStory.args = { + isStakeable: true, +}; export const ChaosStory = (args) => (
{ + beforeAll(() => { + global.platform = { openTab: jest.fn() }; + openTabSpy = jest.spyOn(global.platform, 'openTab'); + }); const props = { onClick: jest.fn(), }; @@ -59,4 +65,28 @@ describe('TokenListItem', () => { expect(props.onClick).toHaveBeenCalled(); }); + + it('handles clicking staking opens tab', async () => { + const store = configureMockStore()(state); + const { queryByTestId } = renderWithProvider( + , + store, + ); + + const stakeButton = queryByTestId( + `staking-entrypoint-${CHAIN_IDS.MAINNET}`, + ); + + expect(stakeButton).toBeInTheDocument(); + expect(stakeButton).not.toBeDisabled(); + + fireEvent.click(stakeButton); + expect(openTabSpy).toHaveBeenCalledTimes(1); + + await waitFor(() => + expect(openTabSpy).toHaveBeenCalledWith({ + url: expect.stringContaining('/stake?metamaskEntry=ext_stake_button'), + }), + ); + }); }); diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index d7c244f3544d..1cea69491d61 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -95,6 +95,7 @@ import { NOTIFICATION_OPEN_BETA_SNAPS, NOTIFICATION_PETNAMES, NOTIFICATION_U2F_LEDGER_LIVE, + NOTIFICATION_STAKING_PORTFOLIO, } from '../../shared/notifications'; import { SURVEY_DATE, @@ -1277,6 +1278,7 @@ function getAllowedAnnouncementIds(state) { [NOTIFICATION_OPEN_BETA_SNAPS]: true, [NOTIFICATION_BUY_SELL_BUTTON]: true, [NOTIFICATION_U2F_LEDGER_LIVE]: currentKeyringIsLedger && !isFirefox, + [NOTIFICATION_STAKING_PORTFOLIO]: true, ///: BEGIN:ONLY_INCLUDE_IF(blockaid) [NOTIFICATION_BLOCKAID_DEFAULT]: true, ///: END:ONLY_INCLUDE_IF From d914bbdcfc5fc0e4b7bb3c7ee1edee39eb8783f9 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 23 Feb 2024 10:31:14 +0100 Subject: [PATCH 20/55] fix: duplicate React keys in dynamic UI causing artifacts (#23139) ## **Description** This PR fixes two problems that cause the same bug. We are currently not effectively generating unique keys for components used in Snaps custom UI. This becomes a problem especially when using dynamic UI and re-rendering the screen where React is unable to clean up the previous screen and may fail to remove old components. The fix is two-fold: First, we need to always have a unique suffix ("root key") for our keys, so that changing the UI content always re-renders the entire screen and cleans out old components. Secondly, we need to restore a trick that was used before recent changes to `elementKeyIndex`. When using an object container for `elementKeyIndex` we can reference the same number value across recursion. In a recent PR this trick was removed in favor of simply passing a number, but passing the number passes the literal value and thus results in duplicates keys in potentially complex component trees. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23139?quickstart=1) --- .../app/snaps/snap-ui-renderer/components/types.ts | 3 ++- .../app/snaps/snap-ui-renderer/snap-ui-renderer.js | 5 +++-- ui/components/app/snaps/snap-ui-renderer/utils.ts | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-renderer/components/types.ts b/ui/components/app/snaps/snap-ui-renderer/components/types.ts index 65bb4d76743e..510e62c0eb33 100644 --- a/ui/components/app/snaps/snap-ui-renderer/components/types.ts +++ b/ui/components/app/snaps/snap-ui-renderer/components/types.ts @@ -2,7 +2,8 @@ import { Component } from '@metamask/snaps-sdk'; export type UIComponentParams = { element: T; - elementKeyIndex: number; + elementKeyIndex: { value: number }; + rootKey: string; form?: string; }; diff --git a/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js b/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js index acb60a1a90d4..9d09d8df76c8 100644 --- a/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js +++ b/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js @@ -1,7 +1,7 @@ import React, { memo, useMemo } from 'react'; import PropTypes from 'prop-types'; import { isComponent } from '@metamask/snaps-sdk'; - +import { nanoid } from '@reduxjs/toolkit'; import { useSelector } from 'react-redux'; import { isEqual } from 'lodash'; @@ -51,7 +51,7 @@ const SnapUIRendererComponent = ({ const isValidComponent = content && isComponent(content); - const elementKeyIndex = 0; + const elementKeyIndex = { value: 0 }; // sections are memoized to avoid useless re-renders if one of the parents element re-renders. const sections = useMemo( @@ -59,6 +59,7 @@ const SnapUIRendererComponent = ({ isValidComponent && mapToTemplate({ element: content, + rootKey: nanoid(), elementKeyIndex, }), [content, isValidComponent, elementKeyIndex], diff --git a/ui/components/app/snaps/snap-ui-renderer/utils.ts b/ui/components/app/snaps/snap-ui-renderer/utils.ts index 4bd47c3b74f1..e5463588fe4c 100644 --- a/ui/components/app/snaps/snap-ui-renderer/utils.ts +++ b/ui/components/app/snaps/snap-ui-renderer/utils.ts @@ -3,14 +3,15 @@ import { COMPONENT_MAPPING } from './components'; export type MapToTemplateParams = { element: Component; - elementKeyIndex: number; + elementKeyIndex: { value: number }; + rootKey: string; form?: string; }; export const mapToTemplate = (params: MapToTemplateParams) => { const { type } = params.element; - params.elementKeyIndex += 1; - const indexKey = `snap_ui_element_${type}__${params.elementKeyIndex}`; + params.elementKeyIndex.value += 1; + const indexKey = `${params.rootKey}_snap_ui_element_${type}__${params.elementKeyIndex.value}`; // @ts-expect-error This is a problem with the types generated in the snaps repo. const mapped = COMPONENT_MAPPING[type](params as any); return { ...mapped, key: indexKey }; From 6abfd32523e611feb836728edd76a453a4a8c639 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Fri, 23 Feb 2024 10:51:23 +0100 Subject: [PATCH 21/55] fix: Properly remove `setInputState` from confirmation template (#23147) ## **Description** In https://github.com/MetaMask/metamask-extension/pull/22828 we intended to remove `setInputState` from the values passed in `getTemplateValues` for confirmations as it is no longer needed. We forgot to remove it from the function itself. This PR fixes that. This makes sure that confirmation templates now again get their `data`. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23147?quickstart=1) --- .../confirmation/templates/index.js | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/ui/pages/confirmations/confirmation/templates/index.js b/ui/pages/confirmations/confirmation/templates/index.js index 5f3bb0c023fc..b32a0fd4965d 100644 --- a/ui/pages/confirmations/confirmation/templates/index.js +++ b/ui/pages/confirmations/confirmation/templates/index.js @@ -148,18 +148,9 @@ function getAttenuatedDispatch(dispatch) { * @param {Function} t - Translation function. * @param {Function} dispatch - Redux dispatch function. * @param {object} history - The application's history object. - * @param {Function} setInputState - A function that can be used to record the - * state of input fields in the templated component. * @param {object} data - The data object passed into the template from the confimation page. */ -export function getTemplateValues( - pendingApproval, - t, - dispatch, - history, - setInputState, - data, -) { +export function getTemplateValues(pendingApproval, t, dispatch, history, data) { const fn = APPROVAL_TEMPLATES[pendingApproval.type]?.getValues; if (!fn) { throw new Error( @@ -168,14 +159,7 @@ export function getTemplateValues( } const safeActions = getAttenuatedDispatch(dispatch); - const values = fn( - pendingApproval, - t, - safeActions, - history, - setInputState, - data, - ); + const values = fn(pendingApproval, t, safeActions, history, data); const extraneousKeys = omit(values, ALLOWED_TEMPLATE_KEYS); const safeValues = pick(values, ALLOWED_TEMPLATE_KEYS); if (extraneousKeys.length > 0) { From cd5a2043589db77bea7d3d405bab41d16e80dd98 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 4 Mar 2024 13:25:33 +0100 Subject: [PATCH 22/55] fix: SnapUIRenderer rendering an empty delineator when loading (#23267) ## **Description** In the SnapUIRenderer the parent will pass `isLoading` via props to signal whether the request to the Snap to show the UI has finished loading, however since we shipped dynamic UI there is a slight delay in that request resolving and the actual UI being ready to display. Instead of showing an empty delineator during this time, this PR forces the loading state to be present. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23267?quickstart=1) ## **Manual testing steps** 1. Go to a Snaps home page 2. Notice that it doesn't show an empty state in between loading and the content showing up --- ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js b/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js index 9d09d8df76c8..1ce5cd82f7df 100644 --- a/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js +++ b/ui/components/app/snaps/snap-ui-renderer/snap-ui-renderer.js @@ -74,7 +74,7 @@ const SnapUIRendererComponent = ({ isCollapsed={isCollapsed} onClick={onClick} boxProps={boxProps} - isLoading={isLoading} + isLoading /> ); } From e16f629a9cf2d6d36e7196bdef4746a81d62dc2b Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 5 Mar 2024 06:26:01 -0330 Subject: [PATCH 23/55] v11.11.2 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdaf4f59cc7e..0a9f241de5ed 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] +## [11.11.2] + ## [11.11.1] ### Added - Adds a staking button to the mainnet Ethereum token list item ([#22347](https://github.com/MetaMask/metamask-extension/pull/22347)) @@ -4428,7 +4430,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...HEAD +[11.11.2]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...v11.11.2 [11.11.1]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...v11.11.1 [11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.1...v11.11.0 [11.10.1]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.10.1 diff --git a/package.json b/package.json index dfcae21af58d..bc3327a0273a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.11.1", + "version": "11.11.2", "private": true, "repository": { "type": "git", From 762c2c387ddf06841c886434ac1c52b6f253ae4b Mon Sep 17 00:00:00 2001 From: Brian Bergeron Date: Tue, 5 Mar 2024 12:27:37 -0800 Subject: [PATCH 24/55] fix: asset list showing fiat symbol instead of native (#23327) Cherry pick https://github.com/MetaMask/metamask-extension/pull/22760 --- ui/components/app/asset-list/asset-list.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ui/components/app/asset-list/asset-list.js b/ui/components/app/asset-list/asset-list.js index 0c3a1a141ff0..7884e28ee0f5 100644 --- a/ui/components/app/asset-list/asset-list.js +++ b/ui/components/app/asset-list/asset-list.js @@ -200,12 +200,9 @@ const AssetList = ({ onClickAsset }) => { : null } tokenSymbol={ - showPrimaryCurrency( - isOriginalNativeSymbol, - useNativeCurrencyAsPrimaryCurrency, - ) + useNativeCurrencyAsPrimaryCurrency ? primaryCurrencyProperties.suffix - : null + : secondaryCurrencyProperties.suffix } secondary={ showFiat && From 224db80d5207b5ebc69a96cbbdc57c1028fa5403 Mon Sep 17 00:00:00 2001 From: martahj Date: Tue, 5 Mar 2024 16:59:38 -0600 Subject: [PATCH 25/55] fix: update stake image (#23324) (#23330) Cherry-picks stake image commit in v11.11.2 Original PR into `develop`: https://github.com/MetaMask/metamask-extension/pull/23324 --- .../portfolio-stake-notification-light-mode.png | Bin 18898 -> 0 bytes app/images/staking-light-mode-preview.png | Bin 0 -> 46832 bytes shared/notifications/index.js | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 app/images/portfolio-stake-notification-light-mode.png create mode 100644 app/images/staking-light-mode-preview.png diff --git a/app/images/portfolio-stake-notification-light-mode.png b/app/images/portfolio-stake-notification-light-mode.png deleted file mode 100644 index 33cbe293392000d65b8efc208d0264b56ec3fd53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18898 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 diff --git a/app/images/staking-light-mode-preview.png b/app/images/staking-light-mode-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..21081dc68fb081483dcdcb8abb174657b16eeeb3 GIT binary patch literal 46832 zcmX_n1z1z<`#*?)ihxQtqI8OMqXN=hBPKD4NjCxm5s^l^Q%V@4ySp1Eos$+AIT+iY z_xHZv|8=hI?CiSE{XBPl?)!Y6=Y(l#C=oxReT0L9L#+J%oemDpy|ugF2M-ADzJ-Iy zOzut(o!=X~;owlR{`0|A)_Hk+_b0BKj?x>P@-h0|yNmla^6K(9IF&I(XbXHCoVpO@ zck+7PxQDk78+esm*uoW|trzamV`V-`a)GgODL#TC@pM7BbWOyEZG8?mwB}y2!BOg~ z0S>`Vcmd16=0jLi`_T#kWSrmtjOTDbK=+k~*l2|LzS843Ia>*(snjCrBYh_YeFc4M zy>}m>(iyEW8fYbxQZDY-g0A03ii-zE4z31M>F02Kvfd_vI-Lv$uF#CIumCFBIoQ_h zkje0CMcw8f6Ua+jUm^*y=o%fQU@Q#{9}i~FN*AxUe$xL{MkRxofEN=(aZSkNj9+ppVGw$ z%jZ1{l;McgKbo6^D)Hg_NGARW&m$!EI0O4I39b8kHx_I3`SjRmA(6#I6+gpD9QcjU zhLjRcrJl_M64Dp1?4u8X@i92CW@-=Xk_qxI`yN{(+NW@Jg4xKyPYt{63Eju=FdI3w zI=*q9@G6hY_d2^xNLcM>o)|uVV^t-Wro!DWmKrW4 z6=(@Q+ktjXjOHqeXV!2Y~W>rwY8MHtaJ+*^bY^t*^Wg z!8?V__>h^igdzhQDbv2nuisBuHUS=y9oKQFN!S4pkoAhO7U^PpE;96CA7*3Q_IVA01BuSiS;QDK~G1t6tvj-^pHo6@?rH7*7bA0o}T?PZ$517$fjBngm+AF zu>D+Z&zMuZzN>k_pp4WQ1wOO(R>L%Z=zY}C=kC2M6ySu<|GU2my%bJh@G?C1( zK>Mys8FpLPsACkxu`g z_3wCV&2J;T&?MO-V5JO!;(S@nD||VP$8lLnZ2B-k2AD2XRz=1NZ%YLMTrs)r%==t8 zBrDKsGUbl)x;x+}&OflDLRi)JD?+L8zQ^XI&p1G&_XCgXym2}w;st__tFGW#!xHi9QkkyDs^u zdIFV#qFJM;&7d-6H7(hI9WLw^LC2;Yf+aOFu|5KAf>vIE12C72C>fr|lAs&JdRa2=R|Gu6TK=+M4R{lF3lD? zRI=kViC%E70oE-k%$Agv!T7bYsSM9n3egEnulGV~p*9vOW==J_h8&V-A0dp+fdj3}cfjIU5}N^Vd!!VId4; zi}wOdF^4yNEd$Q~s8Q{KN!~>zKPqjT)4^B`iQ^Q5CKrtBCOP=IGYEGd#dCrAla$qV zyy^8H5|;bbPft0Gcq#3#3G%Br5y!@9&VMkSsL{v|+6JlLiwjLTws&W>JQMf!??KKi zI3%>xbWT3={+dy&dp<(QWSqq3Q1Eb`qk_PmH*1zuXvK#%m8y3e-a>Na^o!JlKb{tA z(871#cN3HZ>kXw`&0{Flb#Sd7s(FTj6CjM}2Ea|@lEaW_QcfNAYkEGcR?&KmV#r;f z$xbH2_qnmli^|=*2@qcYy$}mwf7Nep?uSZ%)`@C8x;|u%SeiV`H%1P%XF5(%!Sr5Y z#)0z%s0}a2Mzl$BIVTwXQ=(nX<&SZif)OoG?IVk2Fhi!!njogZz4!Bru(D@ z%ctG|3}Dg2F5QSJ_B^*B8EzmoSQH7HO*WvKi)b`Z95%~|STYujzo%Z6Kh&P^x`f=W z;yRl$=9Ey#z6sro-sZ#FWTQpb)6FooZBDa;#Yp}mUH^L3_UWzkQ}!dMRBgcUv@tR- z7sgscprO3e*%(|Qrk7JKn3wiYMp6(`R`-3{X;e;xfXb^o+s`u6&11HFBOXse{+AQ&|n_)v~gKE@x(=u_2s|@;l!kN1c((gBW8jsbZi(%nM zXKiyo6G~n~Iw8P`s;b+_BP3Jz$2bVITr?dGzI{7YvlmpPI@q2h!x}Hh4^^*4>mX`& zR99*mC>h>O;VYDL5pU?H{`uf_Wr`Y&M8EW(pLo{tCWbE~(1`)Xcp&X7Il?!NOO2?K z_^3v0`(|>Z*L!<+>vh%&E!q+o~cn^4l*9us)A6N}q($ zGmFX6!s3#6g6H_m2%ajN{9&S#dn#7hcTMsfl&f6pV}mjr%9)I9HvmQrwiC<~HqG1s z2HGi=ri@C^guzxMd{~~=yCQy9#+~D^uPrceWWBY~9HAMk7Cqclx0Nls?QaM!ouOvS z_HZDIma)+=aQzf0mmynAm_#@nSc5PKjtIsVt8#8>SP^c-W2-vRLXD~TlC_@vkf;}? zp-++3Ypy=X_IXgg;wf&M_yqi6g}Ovjj8c6tTQS%c{3dr+KGKO%b7eET=9?{=lv>u^ zC}>1dMBMg}bbr~c>W2?jdi#Zx9mz^Rl9Mp zp9%(ALC!-Htxiyhfh#ELxEOF_$-S6KZm9J!sBQVju6K3n4!XrI8B(P6MoOt1#hH32 zkME-M`<(|}Uk|nG6M~;(rLtxTbTCjU#YSKhI_BBfWWCTexd6s{j^FgX_jRFbuBWIx zg08-&Du=?f)Z2JID5t{P`yTtz6P@>#HMQ5@AI6J38K@d`j)>lh-|#&ASt-Ds$!2Ph zc`C11nr&p_!J91d0Q`lLdzIr0=d?Dx%y)o?+FEeAejz!JjFm&`ueS~p3GPa}k|k}F z`=x;9AsYZTW>z{G`@3fr#9{_To5T+dAW5H_V$3kj16WrXjz7`|azw)s0<+ofC|NQ@ zdw#}%dx-$InIS4>5~zyOv>->p1BA`JC4Bib)ez{uy~SUW5vz<&fxkZ#fPQ(@d^3LE zwO1n{eJg(SZtL}+aqX1-I4ISdetx~C0TB9^<#B?+=H!NQ;k0*L{CCC0Jd4Dr{^W`4 zxFo_iH}`uN<7KBQ7q)%`$;_?1lE{GfuD`5vx{z;x{ORoIRY4Xn_akeq75gUH?)flr z+mr=-kNyOn-?sGEB!bt~#@Ur!7k=h^JGWIb)c(A=D$;=IPD5~ww@KfV2^gko1Odt4 z%0BuS8+SSS96O3OG)3@Xt1{vUOP6S)ra7^+nR-pZQ z9CG}$N0xEy)R+_{E96Dp=CalNc7N+jT9&gn=Doka^WO)4TW#ZdUvq@ZwI|M-8S#^y z8h<00<}@%?QlAu2FdvS(%KOzkd|0{{SerdGtQXM^=EPR!EGdxm6ujno=Dk z)Qo5EBg3>Xz4$~S$ch7cp$C5ga~>3vYpOUK_Q{2a;Sk?vP+y~yIn)@O?zvjCs3HTn zgw<_zhl7Q!xuVZUxI#s)j4EWB0eGc}^%qiXQfA(>LyUAri!H)-ZXx^vU6xY4T}>Bn zsb8&X?{Tw{3TBCP7zzH!>)%BRnJupDZNCa=U@5SuMUGFi$W&rKiZu$6B}nRvHu&#j z=0j&}q;7L_r!Yi@*s|gFHF<6;L)5mN?s7MB$n3MuhdYxbNn0_>5uI5z)O4T9)bAZGo@FLpm%r))+;>sUba^MGF>+ZZ$Q`YdL}|t!!~L}GSS`xq%;<3ouSIr zs*DC%g13MntQ(&<*OKSi#a^_cVpv(l$4&W<-qQ2?-G2wo2zuiPniQp7F0J(M5Xqs9 z^~jxnv)@+vQyF@@7j4L~{>UsD>z*apI*xrl4qz<(fu$aQw-|>-_|Y(?NgFNw)0svn zL0hfc;v9diSkoJe{M{Q_)V(m&D0LEUQhaBXw&D8cNyFPAquRGB?Ql^dW_)Ej>oN_R z2dY`{A+K_&dI>zLz~9W{`*L*jmc*RX6T-qNb77#{fwA6Q@V!o1Qe`HwL9!xH@9dNj zDB(mLhy?Wg5aI>U9?m{)fd;%8KQ?^I!p&bwnvS9ts*&l-CWBJT0&bArt}#GPqRN0m z1Wmj?V>W47MtM^GtW(ojDj$+5fcmB5bBi49yQCXp(&VZGHN@%m}>zqB;nF^w;+oeAs5l$u;w?JPCv*O5;8b0h@H*1i+ z^d1FqzL3ieq;i=r$J3dVX>u+bn!dS3JI{;PBY-fC~+qb^E zA-JLePFChlPBIvNp*TI%zFJ^ql4=Vt(Que7)ZihKsTLx<`N+s4BW^uQ7x4T5|L~Vw zH^lpzbvYZ55xf|)$|`s-wz+am{*7c`eF>f-RaULwfb)D~Z6X{%YnSZ%Yx8lxRf|R%= zUjP!0f$%{!Y}RkV42r7kshh!)%hVw7xrQWUupEosKKkp#D6nfcZte+(U1 za%r1R7G&4`u>eahCJ0G*CL9Me+uSz2o_eusLYB$)!fa1vDh_r0xfG-8VvW&Z6i$tv zoZSHn)if#h0+kzu%ykHd%idw254l*eGyC3#@qUxF!;p9?&1rp%aN{%*el5u~t?Tax z-NLr)ZP~3Y(&_EGEO$(XZ1$oXtSn6`1?pc8Dpk3Tb^r!sv!tTj1f#QWLJ6u$#~Mcv zvL|H`=>BWe9e1*2!~2I7eK>{nUWg^#gFlDPh_Rw}r!-%-YH!K1Zr}3ZeLu*knzoPP z<~9~7q~xPf$`OQet@@eTH4q3So=y>TSVe(aZ9#V|#4}g0OYrPG$PB8=5c_`esmG@i zYYXi?gtT|h1^1(fI0MMShaCBR7+U7SbZX)nMsEsjX+G|Q6rf*t%N|T!D$4(gxpTNr zHnjp~xLpUAz0MQ^SH*04kZq)cd<1`k zv3pEEHZfQQb{Af-X-0#k9BR80P^VO+e$W6Vs2-^k4MJRO8J**3GxCu z_R~X5W^Lfx4|trmIW=_JBzQm3gg@wx!J|n!YIzjeg%4`fnbEFXnaZ|AlgW;nkTnsT ziuq?PaAdH*I{>|Xt5&S*QhOaqJoBn416cZE=&F*0XWAZ*v#6A~u%%s@7T`CSE<9m! zn7^#sbcz@8EFxLnLc43c?7LaKWVk}_`MybhNVm6B3+u$()-VLLgy%*`WPZ%V*VXK6 zt35R}EU#5pIu}}d{l}uDP37b&FE;`0mCKHboKzg>7P1z%yzSZ3m4bxL4q=D(^Uw^` zf_L~j9{++3YjE3pRf{x%qEB0dULxA#Zd)V>-$t~XBgaWGE+}9o8oaryI0T7wRKbAS z;xwpG@P*ozamf>@aCA{$sS#u4_3R&z@5<4ejMq~I-KuOgV|?9Z8f|Wtga_2CjwDOu zRQ_$6d|6!X`MkGw4IdX1dChBF?JBMi46C&7cO~w6eh=3D*L^YPci_QuI^#Xl#miVG z1zNOSe+L|XyV?J1GeHhKLGZ4Hkq(gF|2r!m*U32kvPTP*Wi1me3`|`~)(vj{l)jO6 zBF-@<`P+X4NxF41BjsvxQqhMq|M3oip)pUIG&m?@3|6bByfVpO-fC|FqchF6+7AdF z+QjZ6M-c<{jGkqmjF>e3fsSZ<^$V@Ku+NJvxMyADfdZzY!7YvisBOQY?Ig6D%ud># z)~5Otr{}FPpV#f+H${Dp$7Kb$pMGSP2EvV9Y&}qso?ZJOtupP7_7pVuFn1XYiiy%S z+c>j|>fkoCdM8Lj=F97N;Fc!^;uOBZo9{neqJIZk*9~qRiNOL8i9|e>!DQo_E4sHv zcoD)zw&;H3)Re79?rb|{(uSr<;Iq#NC@%P3; zI_)J@Lv@E-Sip_ZI$&iE$97P5T(lR+bCiNM@hI?T`O9)wfz$_OLqHVLJ^~@bSi1!5 zz*4bAE2?yqIRpr&ee6Enw2Nh1eq2;Rd$=Nz(yA zTTC+j!iR(n{ck37FAn2N`$7{G=0yx{2V_`=b9Zm%>(oOq70m*-kV@Hx)1>o z6MKxuLFQE!KWSmC+)P%BqkyRV{OJqduA*-)25gMXVO6mDspe$oE{Q7#Nt388Q7K z3p1E&BEAYt>}9trrJoDrnkIMoMZ>FfJ@I$dfDYh6MYqKYF}N8HGE|M<)2&(skUbs` z-IAqLiU;#L@@R^48aw<{7r6tUA=X`IM(?F%GRgJra`djj$}2DF2-0M%XT}(k)c2+= z8ExX

RmKCrE&h>eI}c+mlDuKSOP=}i(Nf_@mcLQtv4+V5Gnkq z=31kdj_G1kiV57ynJs!r?et4_UPaS|)&CF>k6JS}=Sb{5cWs*qXFsjI4n2TLKT;ze z1BAji;E$CaeIyoIV17X}_m#J-f_^KRD2kDEvu!RzW)hL@B)npU7f7jzIdQdRP#O+} zgEE=M4cGgxtqaVy!ydkPaHPX8s5TfwIv2+t0ZS{titNvxt;f6lZsy^|0EcufnoQ{bRNh7m=%b`FXO|u}KQGW(l8D*^9Q3vR}}_j>D6XEVKRP*Vp++MP++D?_BO8j_($fHQJx0JIW)+1iP#po zX;57L`oXH5t6h){-n+4@wO}8%4J!BD`sb7r#e~Yg>cg2dNUx+-(_gLZi*Y>h69~N+ zwlN5ype*=Q_I)wfJl3Xk)&2{iWzKyDc@zz=hD}ZxZSpRwrZ~UVPg#ny($&Wc{;b8* z;Y@3XeG7tQARJr26YsRLmj-jZ+cfW_2VSv^&sNSfC;VyJhV4{D?Kr=xOS?>@?%|Xc5)GuDh~|$#Wu5p zw#PdJkf}6PmlYb!45GjAhsNpDfTX^7e)>hR>U+8lN}eM}MYabG6A;rHswH(07MgNI zGqdS_i03%z%sN?(BnHT1KFQ?=eI*s~piaWue{v@C;)t-Zf@AGZu%rI?4=@x!P0 zU2|h+5F=|FC8uc;2++r1t-d|2^qntZ*(bD*zfD*Uk(-Xab}Gv8d-LPr9v3NZR2<=o z;hxl~;^dmNK}0-V%Nu>dM!_&-)&0ZK{_t?m73-B5=_4kVfC()AZLwFULAc@|){Olx|Cro>0*$vZ zD?vAey)?dv7uA0=pPLt50pd+?JRUO*T#i=&IFX}RehsK?|bpq?bx-bE|)y| zl!bV5W~UrlRC^}KsHrqdYb-w0>n>fg3Q&>3ER0!F2q82-7KZe4CBJsPEb%{{Cu}o1 zs78N@$RhsC=Eb(_?E7_P0$_Z$&yqWuUG~ISdx2dbE1BHf*fFY}I&%sSg-T*x}S~QAszlY)x5Ho+ODDeTa5TXd;sbRnn_B>Yh-(Scz(?J&WGLx#l zJ}WwG#cG|_W+%zq=Q(wdaua?*N-s}4O2&@2p5eVOGnnx@fYLF$_DKQ#Pp5lds;5RLYzA3&Zo4#XXUmt6+I-ANAz=f`#rtjPgNbNH zYbp)4m_E;K-#8${D?e}+mWb(nxQD2{9JsV_;W#5Aia3r6Uj0U8j@;Dl1Bp#`>hfyO z%PSC4kfnO@NPoFlu8}*r;&*D9i3m4fVi8DbuzwE1Q`)Eb-dXX?n{xu+OosZn#&QjZ zvTyo$kbl!rEF($qH~vtd79}9QP>+ooCJb(AIbiG&uBh62^E}73_KFPTSg;+;KkK%_ zA+7UDZpmY>%~B~M=dVwrn3KNPg+&#|VAXL$aj~r9#-zRY>3iw>@%(gKhsbO+?NzYpTvg?Z-m8NcmOug(9 zD$t!S5b9l+df2?hzDuZo@37|8duc=69C6uoB7p9GQZ()6+tSds+H=iVpDj2`hK^tG zvHU!W650E*8%e|2X7UZM!$Xp(;7{ox^OMi>?>%@{ysOr|yKNa%{seO*V5R(Ck0pfV z2s^t07KA6CkYyBq7l_LE?!6+OZZy9}`}m1UC<&4h&kY>7DK+3aU;|iLcsI0Z=kZ~} zQN5*yq+&3eO+T=1O8lJzDhWN%!bw6JA0E8sQYi}KPb~C z7n!532=&!t>%Wdeq?(*}4fEe{7R(~UX6a&H+`KC4yU~Zt3I@Qb-eB<2bWmYav#W^<&REPwq zzX%!6$ww3j|D5eGqcw;q68>c%f@W21n(h1&eNPKgZlCD(MEsRXDNM~UA4Zbv1z4ZbPwec(-kalmgc~YpDo<}pz;=7bQ_v*) zTHh$aSJ&@82$lS|^VR0HUoFO(;}zjW~Clfk3xR{0$Sht>TLc z)~XqQOj1w(AUDvi7H=Xcdn|>5>9g};(={;isj6xN4N@a<&uL&yGQ4-Z zR9WIMqCHHP9ms?lPecLtI2yIbJ*37Ud}rj7nEV}$h1S9z6W`<{0+%qcb)D&HAsHcQ zfvB>l@$VZ!Z3a?rvZ)7j88oZndnrCWf=}Id;!=>XWXy}S^23O95^>vkamLJc00I^Q z^7iB+Pami@)YCLX=c^*=&fdSpV;lTR5!<0aqjC?^xEgTm9KgNW=546ubw|Z2*rP`;| z4acMgR|uhXM#X!nTP2u-bycf94DCE`2TT8EXx9`%NL@N-vNj^(dWrI!D0;XeFVwiY z(T$4P0qG%+JjC;(xK9rSpSb&!<`E>jBZ}~pgSjM&BiNoz(D`Ii$=&F(A_jf9Uz3J} z5qxRcWFFd+m75E&+CD)=C<(^Q<+F`<94b9kK~<4&CD+TcD+m%JVZgMjYN=bx!auBb z+`Ecte)yvTtIiGa{DFYBG_d~TIU*OXD0+HU*81&V zEUKxrcmc%Ct%QUjKpw5$eTV@WX-GxagTmj)WDor9mv9%P{n~xyj2)fol%!lor;<%6%k1D z=O#mvDoV>;h7J6JH}NH4!Z=7q1Em1lW(Y_u=@;L}Q+AtdJ&Uro!}lSL!&qZhtYAQ_ zXZ5gb13KFUId1+2xkq|bi$5pjU}l(MFd=hzeP7GkC_!5{RviW35^%b7*cUHq@9|`> z-fEBJj!-=rf)Um-_GjgAmn4buYdYX2w+;Jwkw4T3G>p6OoMz>7&3J2zpF{!D&-q!@ z+G@WR%te|HTSS9jKh`jg|>$7%bbUZxh?zqdPvW%BMWfsNMfj#2q45#>1Fw|E2xuvuqDk4sR^^ z3Rgr~y=enUWrLn9E7;hW@Xgvj+9+7pm+Qs2$se-gBzYsqlQ|mesK;xGONs0f&nw3a zFR4C&HvO6TPs{gPei5z^)S@@rgC=E-KhOD8TtBdmxU%vOJ00BrRbI{2##W@B_)Tzp znEuSfpkLT531}8D$EVQx*hrjOwgerFw8?W!*MRTUn~s^-nPQmc?zUT1&Lgrf$)GZ( z7|}-bw$!GIXzsOTlgg9+@EG`~h>@lkJ&Oz_lq$1$t-IhaGH7(|^|l?a^wT4l)OMUJ zJbNh#(vohH#l5U2$U(Bh?Ri_W@Zud!;LxSQCpgm}VJ?4a!Rkzs-$F;}JS2F)cc2!kT1QUsZ9OQjQe%?k=$|hN6q( zbv%)>3RdbPun7F1wceF=DqYZ9eJum7&(1JPr;2OIYWOlZPc0Azo6C9pBq2SNf=qr6 zJXI-_Q6HEzAj$zQ_>`bP;VnDQ7{KVSqMhZIwA_K=ad7}hATC1-LiU)us*HSVZhh=B^O$V{{SDnC-qH>6Qe9=0BIN_mCakE1FT~F)O$x9#UJM(6ceWU4Ly(mc;mRHwG$G*n=M;!+F}WBGlM(ZY;@O zS9&Hsv3=9Crl&o_yQ%9udQtl2>J`QkeNh%!TTg8KJ}SpR3#>J+usLI)f^Qr3K^P~b z-<$=oTcauE^CBSX_-*Nndm$nB0dSv}(IR$8Q6E}0+YTsuX$#wvtxm$q4=i>kI6)ug zkONl}J5$0;ew=*jjPg<dEnfRIigyd-eE-8ZE z&)p&1jnaY2h`Lhgg!O z6mH!oYYfT>NR;7XpKW>^TYsH@00saZ&pjwvE6TzGdMHTtygVe|FboH_?X#rwuhp|>HYj~Qo_MIxM%^*05-#Ouo5wzWBM6}zKwqkbc3lU4SODob zQxJ@)2`csVr7eJO5GVB8$pi1($s6p`y-C=+gtKfS7pazcYMB z4}IsU#r|(>TPs(~ysPx|?9lk4kNGYLHWpJ^#O3$8xXko`#hR~jCN>t03jIh)d(-1QBBihz2BeDF5X!DndIaOVMvqIX)4KCd_Nbu9ADf~!;47he&<9V@Cjb) zk!58i{k!roBj+(m|85tQu-&BP)5fYHV^ghGm*E%HdUKrD5!Jnn`BdL$r~l6uVmO6t z>=u@O^wF7O;x*qyBN7YfYQEMuf?asW!xo5}Tyv8RJfor&vO_O%Hwv$`N6!4}2X3e@;Sp4!WWjvBn^Sbx_pERjm<`@-s(sR%w+iSlyKW{f-dUzki-5xu%Q2kOf&P&}%SV`ID>NTe%Nlu~iQ7arppmGtLF(8SpXMyi;scE@dD z-d;1e=A`Q?5HY`Bhpw6}X4y11NwWAoxZb+v_OAD;_a7FYxc<)!>(0!DrKiAqy;S<| z3zg#bs}XxViJ$=K@L8$CZe#`EbDhvl0(W>~kbA&(xTGdiS}U$)NM5k#zj<|M$)1Y)0x>PcnN3m5lu2kqH3jQFz zV<;g*5mBl5tYFAsrOSWfJl70%y5jRm#sT&XpxL<(yPawE4|>@UIZ@hgg)pFCZr%iId-?~ox;5%=pTDIxykM}dSoJz+rNS%wC(nnj&Ir) zzpCr1`t;)9UZ~Y;T>rMg!>u?dRmZsbx$eIbH_tYuSJCNj=EtfS>1k;PCBmwu3TGc}*mHf&_5hEMP%xe%ExY26uwQC_zVoJ8Df!gXTi|LNsnifqGw zq24X;?fe%fVaUB2-`jwpr}}8-t^CqQ_O?IF18?0z*Ta?Cx_-ip+pS!@rD)n~NgHZh zhXr_pwV?}Xmg<=0C7Y#xpy!{g+=*`SlzyIIaB>Wre9QgfH5hX3h8-0ApP?%JAUq44>frE(OTCe`TcarIl{yneEtj3Hjjq@#wP^Sz;p zl*IuA|GOuYc+qHaPG4A>9J-NKrP0oNxl`8qFs!yDtR}j&Imb51kt7Ot*q*`4XiBL2 zDnO8=pY7gX-o5{GfYqkFu8Mk8mMiThe+6}-!dXF%o94Jslb5P@La#ge6l zm6oa%=MkmOI74()m+p8wZk^^QUX9L{^(AoU|9P^%&w@N^vdZ19XHEei)IjwB(s#N8 z4%^9Ujy0kg1~c}lAHJ$?MTB;Hskl%qRnoZJ6=Ltvd~@7?l@K9RQT4uT&;ic6Tk=Mw z@qd-5siUxX%172O1W}JqhM*e@TJEG2QgGp2;(7fWInKYC{VOM5?A8oB?vn^JB#?wB zRJ6QqNHlSqEZomhP~$7y3TqT$iYR&oO5GEmK$;n~r+;_E{omd1BPkiKPP=vwc`u**mEz0gU7A^;ZKyR(+cUuj3mRnX{m)O)&z7RLzL~+h z>Q0~nll$Es&5WR?sNaw$uBS|FOr|aW*syF}S>TW)RmD-Ce%XgG4`a54_Di4LRc5_LY`J)IhpZBK;Xy0wxvB>pHADoUB**^we0 z1w=CsHx>Fdls+b)+KDIPh9x7vdnKfF5;euXQ zD^A;c_c8ygf+R}hLt{QQ9J*ZHa~ngkriFYHHFE;?Z7VvfP`Ga417wA%Px|-Nwc4xN zM9C9^DJ0fY;eR7O#oJB#DJr=9I&w}#qF;o1@-HtuejyWZa#ajhwhy9D13xruDF~5N z?ABSM>F-Pmt|g6W&iT(_VwTJWR4E#1i~E$jfW3Oo?7w^yo|sM4nGVSg8v0xmZTE8u zis~>rGqLlL`TrHj9cMQqalLK@e`x~9$y3KX4XEeXRJLsr*qccJ%2K9kpp1am$Qy|&5^iBu?nEnjyO*BYB&~!<^zeeM70e*f*_{hYSm{D@=chPHVG{EaA1u3vq8*{YTRiW` zec^mHpl$R}>uGX4lO8%FWl>1N{$B zMJV(Tl1_E?e^g$rQl=*ylUtT^AZa7f5B#GzNT)C4W_Y%ysJ=Ce+5Yiy@UYG43AU=0 z6OFsMkS^w0{XKtiuz+h)SQI*R<_*<~CmIUVEn4ddOEp+{liPk2&~TPVWMOarjGmkkQkM@;lccjY|Dd+bGBXJWJI#a&r=5kl{wU3v5VQ&e6pHCcCmUmw8nr4%%A z%(b2`I$p;-bWRgUs7L%mDUGa zZ5~gi%MeI;6;$VRD{n2`9C!}9cZW{1+3Lcb$MKntvGqbdn0O+9xi>%aT?*am_L%RT@6 z-1{4m0IUf)#llNy+~prs)?HaA7jiR*y%q7^TwT4}g7%>1yQBzZ`{|$hj+>QB+`DK^ ze^7h<``{;GVuTxm!jfB0g6puR>GTg&Z5`jU$?dxxt2qhi9q@`K@!;cUO|VcHWtAxwy)H{}w^AnR#!W^EG^82*~eoT@wctG^t;rVU9tPhdYsa;Hn+qeU%-!_RI zGbA)dD4v9Gy&H~{Y(J&E+Ub{>6UQvBUT3fM^0z$=I00e>{XQR=8$Fact7j@B ztYDWxmGCZbqDQ#RA6_oG9lf{HpwgNT=-+1g>V=*T?iD8F3UuZ@z*126L|( z{!I&%^`56VM)v>xl?~acQ!E#qj+mUkr)Rx#J|-K4Jt_AhrZ_?l-{;zhY4|gFyg}#m zRkU?ilt>{oc-Y^t<*JXWb8+=z?izCr!+Km5@%uebBRIVUcE7UMYdP{i3dLTpVwh=S zVj$1N3foYl?IviQR%QX2rfu7E7MIfszjo{mL<{Z890kFev_FIeoR@xp2J$};qoS8I z7_+LZ>J2>qb{-n*Fo&N%_HYOJ6=?Qg^=iRz#=Ej9vR3I+z*41^(utt^W(0<2No?yB zsa`gs8tlSgE>lLjHyBxy6g`}MLaeMK^pb(GNK;LvSFG^Fgakp)X>$?CCs%9^=Hn;T zr6T{-Q&1p(V#2+I1if9NJoy$hJRJ3z43qOLU}s>RnUAY42^n>@MAc4LL)etlax*TA z+kQ?5)7#8{#z$qdv9eJ#EsOmN2q zomM>;(;`i19j|}OmW5y3tYC4kYT@nj{@>h7%#RTrItyAqZf{qyPHa)Y&)qO8RLizB zq|QD01}*lO*1xeb zAdAUo5|v20qz?oSi5A{WI27E#HBDQI>5HhYW}~s@wMJwmR#4B#?kB047R)tIfRV!rI}AZifdZ z*AmPX=(San6nHQ#;_bT%-;z_HwxzN7y%CeCI8)3@E~J$kUc{P>)-SFFI~Hoc20HzXnWD?2+uDF0D!RrskP1q_IgTUjr!Jc4J^X5oqd}70Ji7u>B;B) zZO+N`T?sC#0X4izNOXjW(CosZB(aa`)as$04d3Il)0#}_9U#v<9Ru4LN#>j&i;(a> zA5+keuKIxMgMpxUJX|}wwg^%sthl?~+N1UTY=7JqL`d??U*f9+hqt9XTt7rjrHHZZ z+09J~o4=QI)HhR{f#Qo5ZcQ#k^4u2`&4p__2hWz8AcYU!hR{=-)VHj~QIs* z3erf2fV9BS&5$B3(%q$W4>6SFkkZWnLkbK%L(Kem-sgS4zdzuddq3x%eeOPMt-UtY z5-}FdiesH7HH0b@;)Js=3mA2nasKI0xg5?@R=H(#%yV6<5)>V*KlIPVUSK*oZ;c_Q z*Xir85wMM(X+B3SiIs5%v9_OPFo=<&i`jQk9b ztFlZX%fjRHmom+hpP<#1tMu{djsivoRk$&-*)>i{QX*GbB4vptH5IZ`ErRn zKVWNtlud6tnzzXN7*-i=Os|`+)^x^78OvUb4hoQ42_+>Zo7z-sv{K0;C~nE+ke?GM zrphI!nrEzEhlazZ>+QF`5Rz?QM3VslERw$Xl9(L>eKH}E?Tcah&m%)a_TTVhg5S;H zVJ`P7l=@`$;CeOX3@fI0>0e?IN|pDr@}GQD1T~B2P&Qq$_63r09>MW=2TOb>o~ZlE z$PixM{#n(UigGGJK?x`iUu>qe=D_#Eu1rmU8XOsu&$1$$X1hXO|sPXE}YKN6yrzO0edS{c1lE zRqWNuCBXA2Qn4|95`S)g!J}>-fA7Yv($5}c7K+XUwR_D%*jn=B8}~vx2-9dB@3~cc z_?y%6CJe_2b9;hiF8K< zRb78QW}7Ch#2x(+8{S!qB-d|Kn)%^;@ldO4+@v+iCl4*(lV;E!r{HRXK@Pqy)J?(s zfp=CrN%y?z#tCW-I;pc@ZI#KDDJZqmepv38cXYV8a`RS(`edsPW>QHoU*L}Ci0<_%5)j>5yH z?iju6hp^o=i@w&XXg~kjH>D`TJA(`w78-$9F6dq7twp!48?P1=a12wzHq~MG-0ybK zr{&_i*Vb?hoDa^>;TmF5oTzrv8S2sy=k}d?V^jkZ63ejQf7Hv2(|d8?_7~0pnOl8f zX2Jzky)K!yDwA@il+C#sQ>3x_Qk?!Xv$21z-S27>^N{nZ_YgNTrFW$%&52dU!7vX) zgq&Q=inF5M2#~jKO#iY;5#*?wbU~)QCA0QS8uUaQn3Zot@wCtHs#SbZ3YARMHnuw& ztus;s$61)3JtKQrCB|d+yfLk{+Ifc5V>x8&!$8s3FIga7@7z{l>qy{*{{rBWom;6=v7XGph zZt+)8L)%W#fx+EMu6H_LcCsF2@bteXl)ceB06&=#83Yec$n_$d1r@Rl@Fn9)hXT zwRQ{S8u;PP9i z?2dh+_ZWY}YF&uy3^jCVl^u7)Za+_mab!+9q{p2Br!I7h(F#7LQZDF+&?FOe6r7-$ zVw~yg@Fp|+cHNi8HkL=bsgFVA)vxGst=S5 zUW@eFz!+TW{fTmAoheZKr|+)Y3=ye7uNTtCbb+%oVCKZf(r>ms|p!BLKr z7U?)iZ(5h*ve#&tI#rg;y}rE?2|VqaHI>ef!AoknlN3BrlqoQ69=CLx(Cp^1JqHfm zS}l+XmQo0^^ofuBI*n@#kX+G%)OEOM_3sm@hqoQc1A~Sm%(i|sw%3ED5Pk{g8VY4+ z*rjWW&zxAy9??xgrdglJ0rD}u%GdFe?F#?TJTp;!hQ-qfr)d;iyd1w1tQeoI+wBzA zXP)1wba1VOSZ=k=m>uh+3*X{mfS=h-vgdgNal!4ifZ|1}$x3C82 z+r?@Zd%*}~x*)Zi=ax?XCgr<>L={VU)Z5y~ThREmIJF-puDM8wsGH;`vKT!taAQmy zro^tj{Ap&J8+jbvK`lvQ9X>tyUL5vd`Rc3zcUdCse{f9+noM#h07%}9dBoHm_cit3 zbs*juyx6?UD^jvyJN+r4lj}96G*mXV>-AJ1cL<145&8OJS;r*bEZX3~vRB_lWM~%p z%DrKh`UEl~zCvj9IML^Y)^)&mZ)?+!2DZq*V?l%P00~ppyel&7>!bIoB>X2OcRZ>k zPj0HpS@ku(FWmn#9iPrxc{OEHepPZV^z~+BKHjf>w)(yA8Z_P!uVH`~0NW6A7>ev3 zl2ack&s0ITy;%{;=0F>d=F8URG}8F+64)zo|IwTm?!@^}QBHK`^YH!h&sPH}f_Mgd zUT#F3G4EDzENOHRm5I^30D7Y>XV~@2F(iq_mR6CkTSQ0Z#0XXW);JKEhnS}l2lH^m zmdRN>3f*T!!j8QHc6VJ1prb+8WS*xlle@#P*hp0A=prfZ3V0(d;-P9#rIJBPd7YY; z5fFWcqN-9zGS=81a|z-7{T|ay;UA7>bbCq6o)gM_8;6Iy<&@hFL6DM1{^*8$xk5L{ zYV1u+x)K?N9roqaNCYiAJR`9qp$YwsnvuY?CcQKcUTpiV0gG&svR*Sy9kb2GpT651 zR_1;|ukm+9Vq@P$N&;_X(Sy`s31sk>(*KJC6kT}J#+uGv(tmR#j=kr9xbGO8?Ym5- zFBI4`$~o4TD$Mr zFR~ST*J|l@TYI~nS-K!Q!lB|SSK(jfmKX*49|9KZ3-|M6xf@^o#fL6E(r+6jK&DIk z(U`DFdQT|J;}8d$ziw;?ofhm@N-H((@NVH9ld`j3ea7HA*)>e4;Tsr@wmKY_27!4LpbZ28$IfHHPa(_ntfB;hO#=m5xzyk!?s>ukjU|&%_oJj zANYK8q>aGt$Rbu60)sgyM*hKlejI@x7)ImAOg~}a2QcM3a9HBezOCz6W7iK{K_go1 z2&ocLjn|Vs9DIcebM9f=##G(Z0!)6nkM)mU&d_%W7Om1nh`ZjsbgG;>kJPQyk+iAt z96)p=2VRr~)-O4E%ZPuxw?19#56h#|pTnTs)1+9NN#f%K) zzvF1^=ViYqfUft2rlU#u?;fZ|51tI0pr8DM6?TfuOobBcB{_n=y+D2bLt|{*_IXT3 zVK(Wyhtxz8HO5H-J7ec<21!B7iZ3XhB=mvN6aFN5la2vo4>gC%Pt!(~&T_EBm}0yvt}p&Q%z+XD0=MNG z)CV>{h~a?X7lAD#32rY$U*b(@uJ0Pm9;?muW_~RCI(lW^J$l;R-nA)VR59OUm2&WV zD14rhh4w5pwSku9D5F@4=-_fZ7<`H*zwRFUb5mHkf=7JL9>Tt4tYn9B^9!@ zeMB8t$Vw%C+E@L`bAQkOok z)LG}}MUinyVVe7%8iBwFD;*HM)?d~bniqD0ypS}vI5?2kSCFuYZ;Y$;e9m~CnhB%A zxoD49o>@@9#%vlWx}x#C-%1x!_wJ#`;VO{FsC;&wzDt1YE|1EMk4Xv%8dYFLnl~?3LpUqk{u=zm(8q8Gkw+_Tj(j>UwB* z$8voHO7`A-$-z*KXqtypY%n)vRw^y2It~<**sPja^zF2 zs8LUa>zt2_@U$;e6FD|*1F?Txo7WWsBL!?c;teh`NgJdRw!OJ2j<0SJLu&qvx&##K z2gF-A?2vbjfzTS`ha(=$WD{sP6`Hb*9(;k54JBhN#E*#()!{eq8}t~6f4)nhR1$Cl zYQUkzvHhFt%U3DvVlILm@~NMd+w2eR^0{kDIk zxq8)L5XoImFGT>mZnZ9XI&t0E=)poe8-`{(PuAhGaA2CWO{wWNIaA7YzRlUBCu$N- zOiEMIzmQnG)(v?-qhXU&B{ZR(s95W3is3}2>$Si9;=bZor${XD^c#z<2Q`eTR=wqy z7}04uTUe%e!?VQ0bvYzj$)ufC5*zN=(JAMYJ6FrM_=cL$1qx9G!y&HF}JdsLLr7b8+$ z$+n0$7SAj&8^m4x99sqqDt-xEmx%@~NjbC{&2|qIlcQDuSp2=S^CAiKg+MjoW7Sc= zFlZ!R``Z*~d(8-5et7}C{1;tP+<^^PN&Zm@)WPGJ+- z{l&B&0sHR}MzrJ1b4p4W=W{$^0Z9c=vRJ!Lf_{P_cS;A0?6_Qi+?%AP43wX!SQt-<*ktB-o^?Av##kcZ81Y-?gyXgb%&KgUp z-YC&J7lIalFw&hGPp>;(z;2`<*27H!$9;d_Fi86lVDK#8Q7L59A0aMhAr&?UB}7NI zU%S2#VEbO{qtnE&)<2#fx>knRQH2o+w0&0fgPeV&?@}_!Ysq3^`6J@{R3eS-qz_ulQkUcDK_VsAH?K~-{F6i;vSEC;T9!Xv z=kDR@8N^BXS3TfGYmg|+Z)gO6r&C#!{XR3`l6?`B#7y`HEx#Fjv)1o)l9H5+bl&{& zBrr*5QJd0)4V6rnn`P5+xeENyw8UW#f5+Wuc74}#7>LziEdng|h&{%6d;#qjlG2_g zJaojnI#37$zH1sqpJd^>s(_RxZ(hZpr8}N2*7$F^u6g>nQ1L|aKP z6@>JW#{W4j9B8`-WDkO>#aqIzk~9h{W~pX12(%kldOt?I3~%Hg{nId9I5Gt92@mn(hRzRn8KVlN9K9R*_l0B5+^mNgmaMVgez_Vs0@ zIT>lWFZIvQ8?nW*>iIqCCD+*4+@P;@f*%gvJTdxYO(s*bJMk*&9XqYd0Q*-x()vZW zkOqpnN2-RtE5ys}U#vWz;Q{)t<%vzcqGB(JnNkXHP;KoUgV_CWNC89s)MXP|GL6=`zEkBX?N0#_%$LX0Q0PB7CZ<4_A_cyky;NOzcxoPaL^kF#Zxu6G2N~qXBG{t)UZKAT79jakv>$DM$ zCl+5-{`}n~9x>%XxaJi~Fcgb?3EQU}p<4I@1_U5m&aiq-Zn)BUB+=dtrblVug#;q6 z9F?K)<)p0xLgsPf=>d}$Rr24M?6qp@dh!^)+K57?5i-?nP2>9^Tj}}}PZE_~OGPz1J&fbRw%*YI z1-oH|tVAI<)QN7;cP1_hdXa8&{h;$-HY0u2 z-q>Zw4le!Bm#~ylZ=ktq?ufqup?+w?-&5oMD*j;%9b%I;uxwRt-(7<+pemN$f$J6v z`K{CL#Kj^$F3I@drUQqFZ+tV67v#IsL*L;kbqZ9-M%_?K5O^%Rfh0UvKjnTh_hP%+ zRtoDnom~_Cn%i@A<+1iE^hyhP^(RtbQEi60Z#R&XEsHcf47K>_3ofjJqa@1z=6yOp+wkn?T1#ZT4-7N4x?5Li7)zq72DsgQ;Iz0I50=Zx& zRCT<*Y9aGraCYlVrj7~*5_+Pj{NHzY@?^X9?cA+s|4uylK&@0Jl;A>p)4{Yv%W2PJ zru%amy8R=X+d!c+AOAE})i1B`QL>K@&hmk(K*CebMX@@cjp>-{rfPC%oJIcmwYWaJgZg z-O)Z=;!BNh!Pr%6)qlVFn1n*hRaxid{oXHa1r~MFe+cSgS;XVuVfs&ociVn?x*8F^ z82vf8mQ8h!J`2M3g=lDfge&o(F;mCMd}=$ia!>CjN7UJ-J+Ve$vrIu8(v4lGPtKUmwHc?W7}KK9_@A(}zYHC>^b)tIs5t zg|sII9qW^1r?d9FN@^&M35#HsT%`mJic{f7i!C$^B36SKiXwb{7ba ze0v?vKr#WRKI#?cF~qxIy5>KTME=She*I4DXR}JgFoqnv2#M%ZRb0;$$6@DzuGH#0 zwe#bD^d5Jw*nRJL>s7kTKW5d?%#)exiFKXf&--q7T8GvbQIIP9V&{)YdN0YJj3w$M zv*OzvGG(0)oqd;c=&^37arElCaIE#%$g#Cc_*NCq@ZP3vzvZGn!SVje&2k&6-0|iC z8xH*|-pQ$Y;~-NU(UIHTJ({=F=)HF)Gz+t5&S>#THfUpwp#pojWxU2;(g#x>3uvF4 zIqjliRXF_ixDNPk=3_5M_|r)$efDvZb-pGP6k+BrGTy3_d!(Z1qDK}5p9G&tH%(+0 zdB&^!+UKPBFOGW6c%#c8s1J-2+gS> z4lXXA3kp(bYHIdSotT@Ohr%Pf5e)aYy=BGWWi;0B6@H26kNzX&GvxrwlqUY|H~X;Z zZw5`Z9>u>T0nvJ?3h?+ba+~r@3&mKBZ#q7Z5NNZP_REY-*m`?sPF5%7_-ol>;=sZk z{dR>;9Y;*=PhW!$!c_LFu*yz8|4qHji5#FDc69M`rYoNGnsfHb_c_-=Iz-mgZ%^Bd|-m*u+MvUvJ^k;wD z!zFd1EaF*pHEq9`Hmp}+5`3KTnxE_y!LX6(HH-QIx4SczEMlRpoCTJ+oKsvH6$Z42*A(^*DPG`L}1gPC4V)~4SWrtMS1 ztE#cH?_ew0*MA#LISb!3rg-2mTw;BF-t4ig1aBN;hv0rW87%)(+NG*(*VeH&Z5joN z*%nUxrrD_QE?zu(qu&fTeer}PEvfQm5EQJ7SM&W7bxIga%$Kig_!Azx7Tr}^yfbt1 zn#QlSqnKi&C+Geb#^}!2(_on~)vK{U4)8|*_!@!A{gsv*N%SSaLsp08Do!~2?9S=& zZ~E?Lynh9ZeT+e^#yL961`AY{W9M5%d;B$~-`q2g84%k_L55B-sk6vROaJ5#N981Y zqzo@4r%p=)c*~c+J`Wx?4JXjK7My)~SZL{u2^4kjYQ{J&KMDwIsG zg&SXU^EwihKDC>67=BW*)05V-FrN~#cK(v=ReQ2OASpHy>6{0nRb#VwYs%74`mNd9 z?QWb-w6-BLsm)D&zV2AsW{aVxmygWVMz|(;WA!LkW68dKWo{0-MhQSzQ>`?+F-hK} zI(DgI(P!XgFY$aExLEnn(wXD7Vz+T+$Ju{tOsw$J07S$05PrtCZgs_t1+;JNnM(l{ zS(bC<%CG#7r`cL@+FNI*i%TFs#SFd~UZ|$fpbOGS%O+>ds*dUrp#LZTKQHs7@ zC<8S940G>4;_9&O+@R}rC8H?DxLkV?0X01sMs_Gb`wb?1r`u>+>Dj1!!_b}(HS~TY zU0?sB=at8y$+?8?@!acrP0n<2!oOad45e_Dtv0b=9Af*j!_wQ)tmu|lUnmM;d>^GX z1UUnm+yg?7b_SZfR4OU$i`^Y4fw0x4|5oFe#|JN}G_mnS58hcEo7H7P<|(!&rHA#0 zCKz5Io$A0?a#P;bw3SAEHO^=^lPido-YQO6yZ}X?pqvkOK^YnBR_!)AVJqlOi)g@g z0qf%@qu#ydi1|K4qU_5d5Q1Iu=spAO4VIzxx^VO>d2Kq04Uv8#guVclsA?1&nIq7ar)( zqzNfATE}c=j3*@;j(v9|yUQ?1+mO1brr7O{QKUs_w=3Sq!PEWTBqbA%XR3|i`@VE--RStk$F>be_CwnJwWsyFB&J@fp5!B<5W`;A*| z_(=-<-3Lt4jF8;0)HAi-UpMr>h?N(k%8*mjAs^B5^cj@Q;h{a84CJ&r^W~M?>{`Tg z8(wZ|sutwz#;Pi(VS`{_RR=8??)oM>7#b??c|O5*f95^_@eSy^BaT9}Q!Z&7K(}C* zmtAD;opumpA?mNy>x!oKGXtrR_R9{d$UWTgxk(U>nqGFgL5XC$G*tI72acztyH=5e zotZf}JiMUq$G^1SR&ud7pQv(mT>7 zT7=K?MeK7>J3(yIuB>OLOGVhNGPL8bnhX}r)sDvw-Qf$(iy;+Zt2q${`kasHW8Xo6!a)eC)<4kORT_Bl=g38gMZAuRs87}XD(q5jH! zF`2dr`=+|ncGt%*34NVwRxqC)|5xfgabKfD7}oiQty-6hX8QyG*cYf4pAEnMpQUEC z4gfv1()gxRosV+36{Ve2M#h1Kgg%t_x*ar+A0sgWZtE-KEi3nnC|!0^{@}3n;j#>BI;a2;j=kW8ES&<$=>~; zT#a(EY*=(`RbY+cS)AnI3l_n$7Zvr2x4rvcSQ4n=ff`v7N?g@%)#$x%;Y?Yikvuzo z_MF9u_i`~~sKmUCrd=fp;SA>K5o4Qb_4SjR6B?z(OykAF;~H^+s?-| z*(#2&-$~EV;bUIci}AN~QNK3Axc}$ns^`?%WlXYBnR_icG;uW@3>g|Qc!_-^bW;6e zWaD$|Ujp2=fnxfdEzLg(Bv~nUEL-011jMH+M(APmuwcJ>td6F88C)KAA1je-iu8 zKXtZs7Pl&g!2e*++@-k153KE=&)|a#n!k``Gsv#_0Y@402Gzx!fB{Ao&;*7kBvQF8 zpqgSR9h7u=-;!FlgGv`MpH72OP3{kVzG(k>EDi?;zNXJQ{;eRZ)B2ZFb+62KJvm|y zis?OMo=``=>YMI1CQ3v?Ud=vAIAEZK=+*ZbF~00~JG zD!&Rx-JHc8$5h6*a*& zsdTz3ap@*R|LpKGsoQjFbu2Fbx$t${-!(E*Z|~i@B2_#ab}?U9kxJFhEFqQFm=v%781IV zsjs#i3B22?b6-N|W2(?nFTb#Hujrl021;#T24?0(@(p@I$gw@}EWAT39KwIjrn4S( zflzKg8e9v_A=})fk0312n+7XIi0J)h9&Qm0C|+6dt>A*(JzHTBsSh$dW;J>35?tkEtg{KNRj+LK)?ASHZ>>S=Eui6QcL|VI2 zuQv|ar7q-CQq#$@a^r}$n1-yhKBY#%y8H!f&(4M2)YMq)bjOS8#_?q21ld zBr4*e9@sgPuA7g{ZptoV54cCh{r zFP|*oFsQ>a@kh3IRrxpXi){e_bGUyyF&qv@bSd4Vw|K>6HZ9YG0Bw(qTS)ES7UXu+ zW?{E;KP?wY;&zy`=WW^@2^_M&Ezmj3i{~4u4mpxf;YqO4UQdLl4%Uo|Vi)=U2{iK) z{KN$h*cH$qLKu(sSPHVTLZ`izd_CzhC4y$5Md@B%9o&lcxL5Aw*aCWZnn3(wnce zq@H`OS^ReCN5AZpsFG~V#}XW2s~T(_-8+tSs{`Mal$4|wE~X;i+kleiSy^c3YTlr~ zx*bm%I*F*#x9=89AgI7IOO&0l2ci!`q|OFngOV4~G~4)#jn^CDYIqi355A7-i#m4o z_IjsREYILu3rfTB*5YDY9~z(h)cH@n;46x>W916gMJDWcEQIL%@A6#D=k*kUL`T4D z{d5n?2`NW{NC1rG9nuFrsU>5j&E470zKLm7HlvbUP}{E111|pNxVtp@P8)3Lx+%~o zm|ufD$*lR|V$n8w_o*pkR#4FyT(*ReckyM8^Ncm$O8UU1GI#lE4ZmoJ@!LWkiOK|U z35}aXsB`oB2shAsnR*q7yDdyW4`_tH{dMurZFG!q+e78bZ-xvgT;o+c3TWk!spS|< z1s`+z%XW|Y3mQI=Br(ez3xHms2Fr;5DaX@g&RM&y>UOn~Rys}^tYj)*hWw`aFPX1Ge9riSP7j%Q(FNb~e@H|GMb$xnMAMxX-#>{RhxDQ_iq~C&!+Y4X zQHAxtY%twNSr-{rx2*IZ_fpKs#f|bXa2k1k#$+MFWq{PsV&vU-qZj6Oq!`%`Y##+B zHJj*E9RRaEp9a=Xp-LoNi-`f2qB9Kkp$IO#JUK`9#kJuC)Ua)+JfCL_m-%sMz8;cn zB*7uaM;kVm>ZNO}&qliN#x-vJ{1#f*9QBj9K3nmFHsR)yUkmSe2c1P92)MXJ4lNOM zjcAwOu_OYYlSkxljS}pED73eIwr(^17-8y0|CS?j|I7I7F=r~7$O~ZWrB#^rwiMri zx}E}Dn5W6)bCP47cRr-{18zQ7<0=Vv$WC{WLYIiFz|NPTsK0}D4x>(;;v}1Ma@Le! zYx&K2kH%`2-Bk9vaD~Z+p4!84$h^Vc?*>dXp(Bb;x9z0HriE+|W@RM3U{7B2G?OVN zhvXNT$Jrq%$DLD>M<)0N)?eV2uLgIHJ&XZ9mu|_EuIC^vFS$RFkeTlrK*mq6PLiD# zF!1f=^)4SUfa^8FwrTU&1!1G==NeVmyK5x&LeL`~oLh*JEbXfCwtogQ6meZ$^>(z_ z5%Cb2UAOALwN)PU{jI38#ldPw5E5LUn5DhLF{a_NL!>L==>=f(%uwH(xV3A*q*#zK zIW}RdZ8PlHoIZkM*H>QDN>gW@)A+@4@(z?_#O^jm4N4Yvo=%&|Z4lCP{P5vu7OQxJ z=TXKw*prxh)}oy)0b*|2sE@irNVW)@kRO-Hb!fA379lGB1;F9R;4aC0*}`xBcDT=71i!l>A33q1Cx{@wOToS&baP+F9Z}lJlXK) zVZOUTOV7875qhyTwjOWE*OdVn;Rhhq3qg3_A5(ok zCFhuqm6nLHSA242!Z?EYF2Jvmd;ov*r-pSQNnR+;`As8@xAtEY=9vzRq~tkA*!G0c z!B-8vEEkQg+;a@~?k_bMGqSZhA(_yaiFaB_Y0BvW&_8@1Pj==Y3P4b3#c17@y zy--p$bvjsRY+t<}h}12m zEbK;zoCGF)o|jFE_3KHNuoOJRpYI6)?})Js)oOP*>$}V+?bx8VfClYO%z+icVKFT4 zd&OJdgPuQPEu*Da`=n5@S5wE6nH+ZX!jPoVP)B-WVn&G7g0r}xJN%kfG%S>q&O8YR z?>8eKwuw(SB2kEZnPhKc9rrAhN!_4%j#+P=PasqA=RPSPyK@`k>4-W+1+VAN@Y+-b zcZQZW>`jKvAPAp$8VET{->vPA718Hg6B4CX1ljO&L5??Fqdc5NyYB zgYvfmYT4G4CCF{9&%u*z)&7eLdGFXuP&0naUEyOCS*5=`-0Zi`P9ugzKPu~(plLHs zXBv2yft`}8CgG+&fFF1)=O!OtYB+Y}Q>{sY!z)N|8zstt5ke~hu`u{Hr} zid)$~HFIH#+21P<$afmNjPQQ;i29(uUS?8y`Dxjyz*5JMjh(<;TBE}EShW$V*8u0C z;`F{;DSyYpt(e0e${r469A=$hXI61~_?D}T$GQ9cR;JsA1|mi6pdkr}*VfnH(d^@d z4@RF8_)HKbFV0!w!j>!4|ZDXxEFC$aYji4g>+84FIL_T*Rz!KL1=3VU7 zn#`I_ZDK58u^b}3=n*~2+XVNs!*-osQS)BW^b6Z8wlsFpn?EmizGl45e)5jb9quTO z7|qjb)3mV@_n0nwYwv5{+;;EFs}CxtrcP9(^gpVozpd{)KD}FMr2f33E=tEi}7!)M8<`AfLB3;<8A}Zua66f5I?fkWEXq zEhH-$e6fO)uIl)<<J8OyZ` z?tR$$Um^fO-;&}1OHAc$W*wU(F3u{NX2=n=PV8^L?i0+R?W~C0d0U;X__;Xoj0j3l zghEy>*YMnbs#o}F+*@|a^Os%=p4K7d&fai0pz*ddUlAqOOCX%R*G%IiKF)y$?|y{p zP&Hw0p_#vBQw}(Xlf}!#(2(~ozDL5(>mjMu#V5omnc0bn(5eTe)86ZUZ!i&ezk!C7=0nI-E*XUO|`M%TZiV}SXOD&V&in3lwlZJ`mF7I48JQnFV zn&^7#V&i_d5h(8=szpAK77b}!J~wh3Z{Bn^gC5wwT}3y>0ZB@HJqFlkXzk~L33}_H z(k*+04iiZE8zqFB^G>)aLx#berJj~x@pJFx8Q%u;=`X{%i)Qa!-fTJIm00sFzD%wI zn3{5GFPps*?9XNbAcAv7jx8H$zW%wZP}XN}GcO8Zg3S>MaIIwmIg+z?f5FwL*`?(C zZhK0tcC5G&w$W0msw(4gr71`rD{kW(zWc`#f|0>A6>5BJ3!%&+8*A|VTX+q!^~ zv%!Rk=M>-cM&$Mvx0*Uk269ha#GZo2))V+^s?;*Qs|*>JTQoXP#`7{?C>A)Oe@c47 z#nWZPGVrp?sC;?ec02=W6tHHX`7A{E;f*a{CkE5woDKGl>(5!Hl&D;p{7INX$i&%3 z@iD@*z^!;0wuhW~DypSFZ!2BFKQeg80?mPmkL*-ZU#Z z-g}$#=kiuo)l17$S%?(Zg4JvCDfDD5iSOFgUG@fui%#vhV?>FVL-pGWs0CBgNuGzc z9QEFh?#Up62(0(J=5z0U%QDPMm$h8ZYeel+YB8z+9`1jO zwbpxUmnRL`wts2JsqxmvhD3_iS~6Ph&kX0ykb(fmWmwQq3rMT=>ba;WVi45r-7E%% z*qE1s}u{#ehh2TQnV{l9@&a+F@6seO#;; z61}NdE4s7w2J3Fma@uS@^gahYp>W#qmvVx{Q2;J^HLa{pNC5L!OJ&sR2W1nH#5}8N z3d&?{dO28eER#+V9YwN&W` zjIu^>DE}Ycaa8W_coZry%1K0#=w3q zoi3Xe>8vDGfq$;Y+N%{$eeHDcV?K&l`t3CwPMP|WeT4eZuuaB`O-9{4`RznCGdhNT z*WnZwTgjlqi|Aiz!Ttr_Wz#nIVs}$AHdcA!WYP21$Ium$gT4iC?Vxul5MA z+WC&*ZANFyQ+f82AAp0r#?}9#-^bHgt#x?!WqL%vaC!i)!fDj=vf{8O?AVpiLk@uJ zo6rnL@o#iqFu)`1GI*)}jO-4K<`a`|c!wM#T881Dl}VDmkboV6c%e8n6i8>z853`P zXLX%21`%sz!hng<{08*fPwz1y_f<%6zcdI69z>%fu2;PX``IgI5X3D`^L%HbeG(cj z^Ql$o@UOYr@veMs`(zZ+*r#XuuJC7$lq5SE!#l+lg&NBf_uwH$v?9YEZ~s`^&pcTJ z6@B_74v}c3>0cYR`cei~PEF$nOjwsXEUMMq3Whul_7WpWm_YHUO10*&!JE_X2dAfR zOzk~9;$NxFZ3NR(c$To_pRL2LF1q#cX?3-_ER5O98~WGof_R524H0-$XLz(jhYx5S zhVJ5;j-!A5T|qhezh9a#EK-oHHU=LX45&Q6U4povSN@2UVDkqtaT*x^U=ay>%S1ZU z9Tx#rrfD=E`7>GwO9hLg>~}09fknBUvv~Eih%I(yzJ4=r*d{LQo$511(R4UD#&Iaw zQ0S=*Qu+5TwT$uMIvQLZVAnyUu<}K#x0uZ2=xAP1a+;Zpa<&v}%5*Kq37hTnNg?v+ zmo8+kEC+!U?$%l7nE8q&DArlGpGm>S>%MSMTHAM0i#C>-AtiVxn>-GbLY^phyeEX; zurH$>5r32fG$z)c=G#xXb-TsdD0}~Bqjww;U!2E8o1n@2D(fZI@dDR@$Z$;Sv6X`s zrd#kqpHpcL2YB(f;9}xov_ekH8gABY-!Nypr0#L}WH9uhJv71EDZC;|(}Z2r{mG0w z@8hwoMJ7Q^(j!`T*zlv*kvy9@P0gq+`V5GG2#ekQx~$c6^$AVQUm5`|n{HCIDXUyV zXZnEHB*tS}mY3Ob-KsEG>ru{b`jE2<`r89%Rd*O&|8Q(}(XDm;8p8nfLUqUylR5@W zlkC=85iYE7tOHTLNk`?9|C=M`o^`tAyiM%)dG9gjmZYzi!%O_W!eiGJQhbyKMVQWZq3xzl%g; zG?C8Xj}^d!y5jKmnyxW(U_-_8L9@A#(Kr&Ay5{uRzg+PLb|dxS=zl3Y!~?a)if2k9 zvsuG}z?cd))}$Uo2mPRJ8Az#0lJe_| zs?h9GJQ8+*u1T8D(Mhxw<>qyNO6kCG^$f1MYdy0f4<#rUF5?pFn!+XKaQ!dFjQ~H* z+07VZxxQxxk_>1FUC`(P?14bC23b!YwlSO}v6JHxQ~SzxY93A9EwW~gYCc=|?<1)K zH{WVp<9mISt_7G*+pm8wU?W>fbWq8+dOha2T{}$-` zce3ZT#utFHmmr$q`vy#z<_?Pz#>1M0po;=Gv0HS5YZAF1z_-m~_o^-P`x7?q_1mEO zcW_{mO4?T7V;#+q7VagMBntzj${vo>&u`}`xal4%dBs8tz)ZHwLng&!tp6Jl?6@m) zi-94bMN!mcFJtvtB8eAYKBsMO7`{kJ&0<&&JL2DhSKYQOodunIa^f#8Ix~o}zL;m0 ze~`2V!2RDe9HIJ{k(z>qcU<0G+hurXmcApgl|VgfpMcYX$a@z~i16gEr074N7?Vuz zkOlXYyf-FOf@bT!xcC2^r*!YpnQ9+!d0E^~t~#COZ_s;}B!6b4)vD?Bz*}RysJ|^~ zU98rS`Lr%HO+SUU5l#3u3()II_J7uE_$DE9^G30Kk!4;R?P<*64aiR)8tZS36nIZA z#n`1utGnJ=V?lxJO?-?0U9cE+>1oFvkMta#UL*20iOj|O-zTbRoMYIy2B{|;l|2cg z+?{yBp`}fv|I*yI7$8qs=7-O^gZ26@$~!y@ESqur#280a_`A!%MwWrcZ7uJULsJ2q z8OMXaRbmcs|1&K77U-q^9rhFB&}S%j=gTjsg{Z3ifb!05uTmO6aTiPHFmxV#==qg_ zBmEh^8k_cw=>I}J|B)qPn!MBKR9~?>(FRJ}m}D$xA_S7sEvd*wUG-{)9CzNKJ1$I{ zUHioIT=Bvi$=vseVS3bi?C@-A=(7yk{cGL+^u!ZesWAlq0n&)W;PP z|IdEY0?PrRdEAklgPMDMcRpfM6*~>)If8 zBN2*=jAr)UucS90w+tx^F8^!8cRN{0&XOv6d8Hs~MqM^vh>`;=SA~r0wCUeU%LATl zyL8ci$QG{)0DffosxSm3r~8_8xZaa*L@oZQb*7S3hwVI7$EG**>iq|qnXVmd$F-^M z2yxHKZF98M-SXuBJNj}17mEU?X|)lHJy7b*4=cFzZSc*kM(fM8GyI{)nf{+B*#GG* zhB?CvM1JkKb=CZE-g~#}2MHXq;LZH)brI45)19G1w5lUVVQo3D5b=`FN7M!Yq|b zGt}SjztzA3mu*U)%9F8`CrdQ_FJl>TVr^ClrfnE${raa+5L|i|Z_5|FY5qxoAM34d z($L*iaTyQ#pUpB!4ZoZU+9J&(e$PnHAM0XpaH_=MF=tc10WAzo7edc9ZSDfXe znlS?krWMh+|HX`mxRB?m`n9O1N#C3DTpoSBqt>v|cGk|6;wLMkvHt64W&W&ptD~%l&|+6rdqzdc)M`& zYWEw*4{0CUZtEoKsAJ&&UAC#f<*KrLNF{R^x8FO7+L~u5l)H-Anb)%l6aP}(8Vq{9 z9a-9$I5zpf_-p9YFOtS4)n8XSnXs^xyjLL%LZ%cfQ@|Nn_n4I+F5+F?=?jOWWuPE9 zICZveocn(Z+dkuqC1$JXc3HoDXwu& zj8)79uu?%-I$TCb)ycH?x-S4nXRt{{g{D%C=&08>%sFI5Tx6i7eLY@%HvH$3F=LY0 zd|G~P{l6`K3i+ft?OE(mR-DLe0BVzy69a3HKPToA~%XvfQ4rC!VB(K+{G9`D#Bsy`f zaS>Fh?yL#{9S@wXT3bdgph9v9pdA>-z@EwNTtLXFE1S{f1r_J{E{|va9 zLb|zmxV{CN5fmLDo0gi;>~hw&JKnMOabG7;b%(lg@^blOOCjScT~e3#-uhwyNcjp@ zWUXXoZIGfjAiG|NEb@83cEhUD{44*yLRduiH!-mzJHyLqAq}oQn`SVK{nM8>|Np%6 z0zE&7Az#P*rWKy&ek-<>MX15WSS5r_%x?}eY#oGuPG{#aS|51u_1rNRdG2r(f<08!NgdS8F!x-NjM)kIKUKfiU+SJR zC-nTEt0W`HzGNFrP2N%x+PZiPn14Ctm_3}Hg-%EsO~bMnu{vNs<&kw_4C|B)I_sYO z$utkQrkh!#J$;(;pXs9ZZib%<{BI~PVXc>JK{wV^{AmC0yzrB=SMGhh*SkgPgSfqG zNp2e|N4Zb_V0loRy%IBIM;Z6R&dHj;8q(EyVeN#}$*G8=z#q&efZ0YA!|@Niw!)JE zJIVSTzUWSMs>`M;>gYnTt!|;9!B3w%IDAUwNo}eBdH60TRNvz=W0+Sp8Ep>j8ndK; zjheJzRga1c_2+x4D2<%VS*aPTB#5@0a!RzH67)*&agaL%YAY_b(;bs_T1dLbO~c^7 z_Ln}*;&BsywEx@-{QvC*;g4N@f1AbX3E92;*qZn=)R~~L;eV*YhQ2zD^UfX$fQuFn zm56+oTtVaj5}$0{_j2Le;*!~VaWpkp!-R%cPNUs~JV36rxyRHE<{C{>d71erm zLs?p$LR#8?j$89mRs@4zjle}UfLgj}uo|DiLD%Y34x0GFEdt_aUe8vfbxY`d!$M6O zM4a@koxC#DS~`~v))s?-ETr|s%m9aWeS@LQlhob+AK)5A8uBD&-Q3<6*}W-i9*s5k zSx;2si1SViZaug-UB%ifKFe2|ptF`1&S&v;pCWZD-2*o^0fr>|a@pRC`>+(y+VX%y zDD?~TBF4x4*iKT^`?g{?E$IxnZu}Q|jeaH7FQYK3el4Ib4hd?+NkpUg+}iCYBYUB4 z#`tRv_s z9R&>774zLj-zZFk(&Jo`1P|^-bvX;C+zw8kHVLR zttp8aI=2cMW-zWHBIV@A6Au#ZVg5b?o0{I2Jt$G--w-$o3uF3O-mkPnjt z5p>=y%+AzYrZUx))@Qq7@hy8p?A%*_NO}lbMQq3k6pP7rnfu$pvVwt|;#Qn*`UUJb z?*P_#r=MDQcOw-t2GfbJ;2z(6AwvYFiALS}^F8bdcI#^icQ!h+q88#{lT=cziYYyr zH=kp&-LTNedi@|rr&f)m(6K#>Z@lm3)n;eeFRSr+SF79S40z6*Ei!CX20YSNN$f1* zyOMNK(y(;8eDw5%L|f)SpH=b(xkSgeRg{e6?0I5)0bR3>|HC&f3O*hwd7Dxf7V>(a zR}2g>UtJvIqzB#1x$C}}D#~ap%vBw*hfSx71|8Cf+XJd&b#Ipx1Y^4%dh@ir`Wj^w z#!wz1Jfk=>RVN#=S@=e+>-bJqY%I)mR+v!=rE-dfVf^W}wGDec-T+zga(+#^v~6o| zEo`^KcVmab`yOCDoVGTiwB5AGUXzBi!u1eA)d~m+H`5tQ{ob0c@{$WW+Z0Gv`>t$; zBTHJdA^Yw>{bY)sFZsPIv+jR}#n^6!tPb57G3QWIyzP?DL^09#-9T^418p-sA&7_v zZ6{7Fz_`88$r^SlDI$3#UR`({f`tGPQn^p(>w9UOY#ejGO4dxVQ{yl0AhU1z*n4K3 z5z5y|U&8md65WS}M;YxGpuKWR>wj;@wf`1Y>I6vH=5 zCVu(}@gp-m<<;5Holf>@Y$zYq-)nlHCuQRRmyfq8&XGA>!G-sVb{^{o1h1w_^vWnrV+~J-O(BgTmg9D zurQ29|9P>rFYa zEd^%N>M5_!BD0t^`<8cS_jP3MVjswkg993`gl7g{i3^2`8CbF?e?-GApKGm)Mlq+v z9`qk1>Ao9sA6Z*3DC09H2yS4&x<}Z0H27fVu&lAy6Y;M1SBB1uyL4W;QWtz8?JoO= zf-9f+peZ(cx3F9HxDoN~5$1wCPnT_eXi%J3vG@WqEPIM~^EWwB&roTOQ6))F9XRMX zh=H()SepZvw^yyrx20iUjvh{XR3sh1jK{9ufLG_yFFGiG^BFx>ZByohNXXrEr_rX2 zt_A=$@&YjBUYKSEmEh4fL8DsUVeH(ldy6xBh(cAwPyP(Vi9!l*IVYh6`_UWb379ec zQvP-|{Vt$R*XaTbK#`*)teSZ8f1n0H1p&WYp&?zrSSk0K%0xtp7xj>KZau@7-=Td_ zh+>gA(UXtZFLX4w20_3DNN*@-83Xs;xASyD^jXi8^&WIlwjAYb7>X4__EX_PL&KvMeUx`LHoEgjo!0h`&`tx@PyvRmO7A<;Ue25uTVoPDyC}bfx6x>!Q2P zAFgGjWj?OSgjBrJtDfY(ar{?gO0HT)O+gl%-oXA50r>Z;&99_Eh8XemP>RurJ;#;n%bf$%^FDtPL<8flK z`{;>B!?9@McLe;6*+k!*cpxYno=ucZh3h|!X%8+|8MX1v0i;-OnIBkmL(Sd8N^DJa zUmDMpJ{6Yuag7@$m-UXOkGhEU6F;E>Y2^~H>~nFR6fNSEwnP{5Q5$zKBS6fWyx@#! z+OF2snsjVhPp$`J)&&3KkIg#&qzvycvOX+KKDejqj`Mjh7-hfRqVy{9 z1UW9vCd{yRf2JsQJYcO@q)&JD^~cL6pH}cYhajtq_e-tmyLvi4(Lvm&E|#;|qL4UX zfh5iWzaU#A7NU}6oVK5P;4tg{aU(%x>~03*IGLUb0L7_it57eJCr;!PA!>XIDH zhtK?^5-0i<+7P0Sa_~X7s(8o1ZzUc1X7- zU%%WRq9|EL-xQh&jS%PwxsV`pYLJ>gSHgS`>B*$G@`_^P0sp`KG6V&U^XMQ)rRV2PkW(-3z_yRDr*F=Hl7J z3k31-p3Bmp8@8y{dk;&ex@t|>V>2U6y_!6_sb@LD^n=SZ%E9KVHl4@CJMG4)j>0Eh zMi)uDX|xE*HA#}_b$NLMZ($EBi#xYDOID+}bhL$xAq3nRP-A{3r5>P9gLq}!FF=1EpQ1IMZoE^o*gDcK| z%jR~=wyk(!h_=dMIQcuTb5=K72@bm+xTQ=~+hUy!!5|+`WlJ!N~+%-)%{BlQYqye90oG25pPj~F16wd7wzMmB#W92m!alHPoSSuYoFL2ZeN zf$wnLkzjs<)ExE}7fjTBYewb*IZf|dtJkOI%G9Jyh4l-dW8@l^ab)>FEDKftsfG3L z`}~1ylENq|PrfFR3mW(sZwy6&0=XFsXsA4JixGu&5Z-x}5EHxVfwh*O{1bt*g!JTM zBXB)$?1UlRL>t|u>&2HmCjY1)!(e&rVsJfB-OLU}H#?Eboa`*edR!QbACs%TAB$5H zmX`g9EP2WzunKO~(m2uy)_X+96gYVqfV1<#%~<`i7r+{PM-eJcrxrT!-FP949aaNp zacq5JJs1GMrK1-PdUPnGTWQMc6{9FGK^6P91=mYiVcQxg`b zn*w7V7wKh=Jzh@l>8cyDh*)-|GE_NoIX38T?Yo!1?VR(?2Nm(KI6oqnm-V^$zRc+x zL&v2s$yo~TvNPxz;HYd#=m`wvb%EwTxRn{O=3m$UW=cN%>lGoMmnEXZX2;p*M!DIu zHuYNS(oHDtI;SrLhCZzL4PR9OskAV2ZPFe66)OM*gKrm_gkMAb&Dy^GB{Z zIYd(nysa8TQAzfS0Fo?2RB=oJi9LK)^wbueK)Dqpg<{Xj+84LDb23 zEx*#jp9YeSx*{T(dD!3h@h=Tdj`<=wztVTHbfn-8Br?-<0t-!VnoPVHelpuv`{~+! z)br1a0ZroD5)`1x8|)C0s&72@i{I{3U&k|3zmHD41v>?>=v;Bmom&H<&1Mp>pS@v# z!L|-|KFy0r7iLL_?*4V?|YRy z=oC12D#X%4{yuj&`iT(GEn~M{cu$rWVNX8ekt-HmGzi5A?nv;jMA}#(GsltpwYq4O z>XRrUIc|Jhz~?+wT_I>k%=w+19ozDdNb->Cwh! z+euVP56pPk>a~Q={LL(M63WcMg%&%mdSXzzd3kP6KfMMrWj6;~NXw68m;o zo1?_s`DL@7@*Dc`Un!_&TkW4K++mRQHJctUsQ_u3u#hzBU=x~%ou+{n@Rzrkn~>4|S9P`$VmZ^QHne*h#Sz(*pkh>YUEMx{ z<`lw1-4hXsU<-)U(qDA(13R}XxM{aMvN``9_m%%B>dZi!;j77?2;C2!6s?f8@UB839F&nNr}zGj@xw1L%o`+2-Dnn<L8|OCBMu~H zMe~Dmlv?g>dq=i|`0n~x%V8RF2acZ9p3~x&TG;Fw14LE>aJ+hidW8dq zV7K3fiX+R~l5dYG4ZS?uKzyv3Jh~|cQD)LPP2i-c-cr?0YXT`$X5%RwW`)<4&IEbB zvn?q*znh;zc#9VeNZ+*x)7trC9D?w?2za#+nq82Ax?Hq#(T5REq{t_*BlFc=Rllwu zFnfyhL)oH*wYyplK4;~bs(X^c*<;;x7Vp}!QmQ!>*;gni zEH9+B-%s=a-9jMl3cNRuY_sf0+2J_fWw}z}Mi)GJJC74s{?9w}H3*$BBWi6#FA&Zq1U4+L{ry=s}jc}9pQ!l|Osma@98MX8zPjwK6^O2|#MPYYzkam(#9N!Jat^0BSt0n4_)&=A}6{=b=5H>MVz5j4kQ4)`-i4>G+X?W^=ekfWch&E&i!&cD!By>1MiGp)~Gj|$G47F{no z?_c=!Ky|t}2^p~~4>u&9DM$`Ozpe-vP<uqhShGpKp;V|eO zA|*Hr7e^L2JPqHf!9qiKF;-7eR8{xuX3i z*L&*yulf%Q|JYDgVQ)p(1vC6Z2@Pqe^zSjI(CgP^))fl3hL54OkHxPXZQ9LvKn9z2 ziY+dUg&h#c(IrzI^>)vTH)rV?x~@AjtJKy{PUh~DRoIBne0&7Vh zk;s@%8^V!&HvF?GmbaxZ*!}hud&RBWKLt8G*f{{W` z1nRekIiIi>e|goT->D{q0oNC{BW3um-lrZQ?^T}D(jk>)2HR<-*@c)9Q(mB4DMln7ETjm` zN;R+f##%A+AdG8)&>&XxkhisBV=ja-JNxo0aovTN}KD>(@=e2~C z07+mi{|N!$68q6_|n}n&!006HBJek3=9-%eB_>a{3jVB?9wrM8Z(+%ln zI+Z`$7WOZ_ZWO|InzuJT*gWU)u&e*}?vM5ot5xZb7m!2=9=juWp8kplg{u1eQJ@1f z(se>wocWnPH8d&6y})R9cu-2RAvtezA|u->2K^9XVXlNjB6Z}hk>#kB1@2pe_?4J= zI_4W-&iNBCS)LXHS(c*9(Y^DRSXGTzFHm5&ohI<}RX3l_yld{5`L*Nej38D@g`W~h zkFLKy_{Qx^im0;p^=u>SdIWh$C5;dsMC~NoXJpgq)rvJzGh*b?L85^gzEh)2wn5-f zi{7|sDIinHXoz|<63-M`HrAJyf`)VVitK~Yr6iU_M01ps(!r(2`j)Fgf?09dzcka~ z0~8p33@`D;qgPKQ+js9NZGm9WNPkY}qO2~E593gQ^LLQt-V|q$B*GZ2LbNY{_TdKwAZaJY+x` z_o_I)@Y^5fN_?TvqNtHMeHb(*%KLgd7Qt3A3nx!LQ??{_*r&Ol$g;QoGOSL3K( zWYd|41ITXCRuqWB+@;F!2H;XkJbP^@QWkG6Mf2*6bqR}nu4ln&RKNeBUD}W%aVzB0 zH%~m2(Gpp2MJC%0`gC=(ino@?CLx82HqEbFyx(4kmDqE~y+XisM4G>$LC!g7A_p2S zDOa`Nsq!J6BAX~jlCst$R1Cf#-LTpDMFqCLqV=js_lrxi{>KMNQbcq^4qnG5ZQGjxdhyZr$mN>C&oTyy&d*FcgQc5>T zub)ahT<%BS=f?ZElZ<-dT4No8V$0be$wId8D)mD?=&8&j_FW|kF> zg2RIgVw|SAUDcJg$7#!&Dwdb?ha+RP0DsfRR#J6a0wTv}k9q0LaZr4e9->%jKWozv1H4axCW!Rb(tu4<8eSQX_6k~7rcGjSh z^d@IeS0TtlzUQzeyG_*3klO~p{`j>0`RZy23^j*R?XX4F2XIlDtKiv{vmHe8%+=jO z##^L%FRZbJ9xy<1c}6Ml*1Go0_tOp$m2O%!7RRVsxv`Pp>|c>eBD_sGAs1CE*-Hee zo39qFKq*D|L5p zbkBd&(PiFkwd$gHIM1e$0K=Ige6WXyf zx@=77#tIg7;}d%_WvZSM*2Sfz^r^*(_q?--bNhCC!`khTeeg*Al^Fk3D6!S;Ec{^t z-fDL36%$TkU!C7eWW21uhAlVtRs9|9Bp&9xs%&O@s%)4ircJ4hi_3A)NxA*)z@czw z!^l|Ij>FnV4WZ#|u|&Dtvxl{HPX7|B$YzC@*oBs#uknfRJ+lO*7}K(+oI5PF{ss&= zMxurneugMNQ^85s!t!*-1E78L^PYG&n8&~Oe_C_!RflR=mfA4S4W;*3pQTtdxJ=~h z(YsW*;!Zcdec}Iq@e2kF9Fj`jSI#m&as|=WXXJ2I?T^g6D%hzi?`xB)*NqD50>#{+elkhMRpuPFw6&nTezZbkxIZq5`sC_G$#op6hA}(LpX!p(|7&a$(bZ&T9&-a`*v1#O;DV{MG4cgHX%N% z{1{6&D;6_-RJLr;hj&E<{Kv?S1c;KIm47d?;6NKz+^Dq73&oe5Vqz9nxEL;DQH7)f z4`<9p39jrk?XSv0GPE&^rrTHrxqB3(%uxqAV2DFlOe9oV)tM4nVItwAfIUv8D^q`cqhOSVnK$g(yr_9)qnpo zp%p$*!y+8B&CEI3>2hClVZyHVfQbm=T^;S7FIDg;8V|WbDrgvtRNzr~$5@|d1mLE5 zq&Q~fDm>x&O7Kk)A_LTJnS_%DkeYZda;n)TnCo@2oqB4DN5L<>Hjrfxr`!V5 zLvdxEwKF?`b~;Q>y0pJo7O+60vh1gs&hK~ulcj)1*Xm)%KsoZ`WATxU^6?>K2|1}` zGhUW1t~AcQtw{5gf|%c)${8{Ws5;P`c90&sR%_xi1**Zcd+8r#2I~W1+fIuQ%PYu; z$2`tyhY})?L*p1r6%ZY;$kb}s`IRZIeb-}!h1c^Q5lWoJDsf{a{$3x%fGvc+24=&r zC${}3`5h_J@F#Ve?ABG`J#zsdpoE!|^n3A0kFQ;Ov{Nx;EIw`Rwc3 zf{<>m#&C^wR}VjA#FD6;$HVx44BkLqk*6OB1?fbiZ{rFfj=n30scy(81c7>vttuTt zYiR4KZyIsv{OL|sRG7o{teC+;X78j7MBfmRHm%;Rkh!;1{tGds1jaJ+GMsGXI8?^E z_hOeB-6tl0@E;fh|F~}#1$))CUo^_CL8$*6s&&R%>vQu8c2e}Zx?@wimC6=2?w{dZ zFNVeL;tB3Bw*?Zz#nRs*;+Onn?j;7=Cl-n!%^IcPxXBu(8aJHQqQ_^p z_c{HR7yUw)E z-1CU_f7XfkRSrUvs1#B#-I_bx)6Isz6Q|1};RQ%aW0S`}t-UF2iIAlU;q#*(k)^Vg z%yv=&k5auBO);kfd~);?nkfSw4VHMz*sp%ZYHVovWs140gm4v6exsKc15}E`@VE1 zFYNfMgfKX^je!KF9UgH=Io+s`%cQWY*ar`%m?dXgqg!my3l;jtul@NkMOAPGG!gWX zN&b$S2nunec~4?+_|tnTj@zJ@g$v*3d6AwvX9z!FXrq=gDJLWT$bb{D4QW_j0GYwM z8NtO;omID2AVnm1{#(FzCrKsi---qx+7jN{BsTS|rrJAHbVsGIQ6@iNQg(!VuWTG9 zUOvmRBP(_(MA4u}{TVMfvMtcm%RZIc`yn-MCN`DP!jm-uCz*#u?I|Dm7GcQSrHa zaKUmX5AR>TCgu_yKmJ^-m%0ky;`?spT^4+B^#Kv=clRp6Tw*M`?p>gq{ce0h|25hf z?&uIK^D#}IFb&v(>@0l;J{0iqTDoo0`6uNR>GPDc2k85VYdlqeuH*=DqH8_A3fnke zAdV9{bp@mm4dum%!U?iOG)yxs!;;X%g{6i5 zMk(P(QUTGj0__Wct06oQ2evZFC-PI}Lte6?nl4K9$+P*A|?e`@u^yujHqF!a;#{U{&z*A*5TU^Sy!UAGXOgDqR zZ?B!}8l`@N>agymTyDSLI816n_LRzmBYPBqi9x`3KW^eJUOfYfjpU2LYfL=JkoZ>e zYq{_w{lm3Gs^Z1y3o&y|ZO@8*x4{!u)xd->tw zgQYE(@#?OhNlS|gUs2Un^uCh-Rw5++%xi9b!g&sY!k_oJ6p9m3H#Coou>IhJ(OqrJ z^{-mJKwA_+qwhb?3WbFLk0uTuHBpm_X6CjW@9MAys_~+7=f_gd-LXD%87|w;#<@!A zxN{H)?LS!gTRLxAX+3G=LhAZH3{%zv8)m$30nA&Fbj zwn@ndUN{RHz%p9ndQ`ZO>G0v;8@3VEcZ(Lt6@|luz&z?cW(M24`3()-#HI(Q{VX^` z`R@F}iJ8;V2kMMFG|3wwPkWz}#$1z=lkJ*KWLP>Q9r#@Z5BfRazOpszZ}3lMKd0A+0h%eL)+VIHW^BDYXS4Ntl!8 zIij-`AM{#t$L2B}R*v02bIw^7DzBTIYmY;#s<9-+S~2&3AKo2LXrlC)n^OWv_=?#9 zbagy2{6*&j3bJm7t4^@9-wki|D|d>F#Go8tslwlrqKR24a`s4P`_{u%k8@L=kQWA) zD_(t+brF~OsI1@qbm6yt3d6=~gNOPOV z;5*q~v;vEdI58B$`;$a3lx$6rGJV~~Ui&$cuKSuC!gk_~oOvK7CEKV?y@obSvb6E7 zO-?CzbGzwGv8*S`#8Qk7m=wFPd*fNHFi7#e5=-XgWB2xA2zU z&;9KJkL=I!Eg!nlk01Y2-P7As*N3GGvG*n7&qKdS&3OspvfVM3j}_K2eLWG-+Xk_C zs{lv*M6ftJiO;4h+Db3d0LL@JR+-CwBgDs|N7F7yT>G zc-nzS!^bSg%*}RgE&rvqLniJtjAqTbd^nAHR)8B`DY9dpXDM_jnkpG;u5ei{U zl*wWPn2g*=7_0eHN46lmvn+jFp-q*de00Cs;f7=NRn&9C^zY^-2hhLTr`h_O*(QV< ze7G#Oe#u>%01R)D)CwEfbNlyDHccmQxt_V`V5SIVPC)ezGE?(}o1@|4;p}$!c6755 zhNQD%O}Mu`B$_gug6;zn@rphN8^Ix;#jy3?6QpQI8UGX~elySc@s9PVRm}FOQI6Bh jgOh^a!dRbSB9Tnxwfnay;i`*kq>q+{{*yX2`^f(XoZML3 literal 0 HcmV?d00001 diff --git a/shared/notifications/index.js b/shared/notifications/index.js index 7e57c92ba9c0..ab1b8ea8f688 100644 --- a/shared/notifications/index.js +++ b/shared/notifications/index.js @@ -183,7 +183,7 @@ export const UI_NOTIFICATIONS = { id: Number(NOTIFICATION_STAKING_PORTFOLIO), date: null, image: { - src: 'images/portfolio-stake-notification-light-mode.png', + src: 'images/staking-light-mode-preview.png', width: '100%', }, }, From 1023aa362d91a70334fc757ebd427338d8a5b6ea Mon Sep 17 00:00:00 2001 From: Derek Brans Date: Wed, 6 Mar 2024 08:53:56 -0500 Subject: [PATCH 26/55] fix: set isSigningOrSubmitting to false for MMI (#23342) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We previously added a UI validation to prevent confirming a transaction if another was being signed or submitted, as it would lock up the UI due to locks in the TransactionController. Except this is impacting MMI also despite them supporting this since they skip signing using a hook. The quickest fix is to literally just disable the UI validation using an MMI code fence. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23342?quickstart=1) Fixes: https://github.com/MetaMask/metamask-extension/issues/23343 1. Go to this page... 2. 3. - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] 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.container.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js index 1cc1685a6031..560eb4bd4eba 100644 --- a/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirmations/confirm-transaction-base/confirm-transaction-base.container.js @@ -264,10 +264,14 @@ const mapStateToProps = (state, ownProps) => { const isMultiLayerFeeNetwork = getIsMultiLayerFeeNetwork(state); const isUsingPaymaster = getIsUsingPaymaster(state); - const isSigningOrSubmitting = Boolean( + let isSigningOrSubmitting = Boolean( getApprovedAndSignedTransactions(state).length, ); + ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) + isSigningOrSubmitting = false; + ///: END:ONLY_INCLUDE_IF + return { balance, fromAddress, From 821df47b00e6cec888b8b7c97cb5b37bbf8ae392 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 28 Feb 2024 20:40:47 +0530 Subject: [PATCH 27/55] feat: update PPOM dependency to 1.4.2 (#23219) --- package.json | 2 +- .../__snapshots__/blockaid-banner-alert.test.js.snap | 12 ++++++------ .../blockaid-banner-alert.test.js | 5 +++-- yarn.lock | 10 +++++----- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index bc3327a0273a..ceb69703a229 100644 --- a/package.json +++ b/package.json @@ -223,7 +223,7 @@ }, "dependencies": { "@babel/runtime": "^7.23.2", - "@blockaid/ppom_release": "^1.4.1", + "@blockaid/ppom_release": "^1.4.2", "@ensdomains/content-hash": "^2.5.6", "@ethereumjs/common": "^3.1.1", "@ethereumjs/tx": "^4.1.1", diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap index c8ba0efbb9dd..6207402c6d2b 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap @@ -50,7 +50,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo Something doesn't look right? @@ -142,7 +142,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? @@ -234,7 +234,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? @@ -327,7 +327,7 @@ exports[`Blockaid Banner Alert should render details section even when features Something doesn't look right? @@ -433,7 +433,7 @@ exports[`Blockaid Banner Alert should render details when provided 1`] = ` Something doesn't look right? @@ -527,7 +527,7 @@ exports[`Blockaid Banner Alert should render link to report url 1`] = ` Something doesn't look right? diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js index b34d9d9b0e0a..810c16f7424c 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/blockaid-banner-alert.test.js @@ -1,6 +1,7 @@ import React from 'react'; import * as Sentry from '@sentry/browser'; import { fireEvent, screen } from '@testing-library/react'; +import BlockaidPackage from '@blockaid/ppom_release/package.json'; import { renderWithProvider } from '../../../../../../test/lib/render-helpers'; import { Severity } from '../../../../../helpers/constants/design-system'; @@ -243,7 +244,7 @@ describe('Blockaid Banner Alert', () => { const elm = getByRole('link', { name: 'Report an issue' }); expect(elm.href).toBe( - 'https://blockaid-false-positive-portal.metamask.io/?data=%7B%22blockaidVersion%22%3A%221.4.1%22%2C%22classification%22%3A%22set_approval_for_all%22%2C%22resultType%22%3A%22Warning%22%7D&utm_source=metamask-ppom', + `https://blockaid-false-positive-portal.metamask.io/?data=%7B%22blockaidVersion%22%3A%22${BlockaidPackage.version}%22%2C%22classification%22%3A%22set_approval_for_all%22%2C%22resultType%22%3A%22Warning%22%7D&utm_source=metamask-ppom`, ); }); @@ -264,7 +265,7 @@ describe('Blockaid Banner Alert', () => { const elm = getByRole('link', { name: 'Report an issue' }); expect(elm.href).toBe( - 'https://blockaid-false-positive-portal.metamask.io/?data=%7B%22blockaidVersion%22%3A%221.4.1%22%2C%22classification%22%3A%22error%22%2C%22resultType%22%3A%22Error%22%7D&utm_source=metamask-ppom', + `https://blockaid-false-positive-portal.metamask.io/?data=%7B%22blockaidVersion%22%3A%22${BlockaidPackage.version}%22%2C%22classification%22%3A%22error%22%2C%22resultType%22%3A%22Error%22%7D&utm_source=metamask-ppom`, ); }); }); diff --git a/yarn.lock b/yarn.lock index 05bc18a5bfd0..7ff6dbec9f41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1683,10 +1683,10 @@ __metadata: languageName: node linkType: hard -"@blockaid/ppom_release@npm:^1.4.1": - version: 1.4.1 - resolution: "@blockaid/ppom_release@npm:1.4.1" - checksum: 6fff1d24cdfe5a1457b7f64b169f225e67ccbed48c3f5d61b4d24514b7b60cf67bbf130808d7b9cd88d490a86d689afd4b90820929d140526fcd8759b3a4bc6b +"@blockaid/ppom_release@npm:^1.4.2": + version: 1.4.2 + resolution: "@blockaid/ppom_release@npm:1.4.2" + checksum: 5cf85e2f1a731036db02e337b9048a05ccf759890acc5b717b7fdce68a85da7a4b36675ab5478f4f29a586ef74af83d0efccba228972c2a806893bb82c8fad54 languageName: node linkType: hard @@ -24037,7 +24037,7 @@ __metadata: "@babel/preset-typescript": "npm:^7.23.2" "@babel/register": "npm:^7.22.15" "@babel/runtime": "npm:^7.23.2" - "@blockaid/ppom_release": "npm:^1.4.1" + "@blockaid/ppom_release": "npm:^1.4.2" "@ensdomains/content-hash": "npm:^2.5.6" "@ethereumjs/common": "npm:^3.1.1" "@ethereumjs/tx": "npm:^4.1.1" From ee6be99fbffb1de8b15b0cbaaf18fa8dce187f8b Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 6 Mar 2024 21:24:25 +0530 Subject: [PATCH 28/55] fix: update PPOM to v1.4.4 (#23345) --- package.json | 2 +- .../__snapshots__/blockaid-banner-alert.test.js.snap | 12 ++++++------ yarn.lock | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index ceb69703a229..5880b8f6f593 100644 --- a/package.json +++ b/package.json @@ -223,7 +223,7 @@ }, "dependencies": { "@babel/runtime": "^7.23.2", - "@blockaid/ppom_release": "^1.4.2", + "@blockaid/ppom_release": "^1.4.4", "@ensdomains/content-hash": "^2.5.6", "@ethereumjs/common": "^3.1.1", "@ethereumjs/tx": "^4.1.1", diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap index 6207402c6d2b..4d966a68fc9b 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap @@ -50,7 +50,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo Something doesn't look right? @@ -142,7 +142,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? @@ -234,7 +234,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? @@ -327,7 +327,7 @@ exports[`Blockaid Banner Alert should render details section even when features Something doesn't look right? @@ -433,7 +433,7 @@ exports[`Blockaid Banner Alert should render details when provided 1`] = ` Something doesn't look right? @@ -527,7 +527,7 @@ exports[`Blockaid Banner Alert should render link to report url 1`] = ` Something doesn't look right? diff --git a/yarn.lock b/yarn.lock index 7ff6dbec9f41..dc34aadc5327 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1683,10 +1683,10 @@ __metadata: languageName: node linkType: hard -"@blockaid/ppom_release@npm:^1.4.2": - version: 1.4.2 - resolution: "@blockaid/ppom_release@npm:1.4.2" - checksum: 5cf85e2f1a731036db02e337b9048a05ccf759890acc5b717b7fdce68a85da7a4b36675ab5478f4f29a586ef74af83d0efccba228972c2a806893bb82c8fad54 +"@blockaid/ppom_release@npm:^1.4.4": + version: 1.4.4 + resolution: "@blockaid/ppom_release@npm:1.4.4" + checksum: 71f6276b21a59bc3b16d3335a266d199071e98009bb789ce26ab066da650b72068dff7743c3fbe86fef6dcbcef1eccef0e90362686283865b34514a956a5f4cd languageName: node linkType: hard @@ -24037,7 +24037,7 @@ __metadata: "@babel/preset-typescript": "npm:^7.23.2" "@babel/register": "npm:^7.22.15" "@babel/runtime": "npm:^7.23.2" - "@blockaid/ppom_release": "npm:^1.4.2" + "@blockaid/ppom_release": "npm:^1.4.4" "@ensdomains/content-hash": "npm:^2.5.6" "@ethereumjs/common": "npm:^3.1.1" "@ethereumjs/tx": "npm:^4.1.1" From 5208d3f37b6356fa3f0bdd81cd40e3ff2c9275d7 Mon Sep 17 00:00:00 2001 From: Victor Thomas <10986371+vthomas13@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:49:17 -0500 Subject: [PATCH 29/55] Cherry-pick to 11.11.2: fix: Token Cell Setting and Token Symbol in cell (#23348) (#23355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** There were no merge conflicts when picking these commits Fixing an issue where the Preferred Currency setting appeared to be flipped, and a different issue where the token symbol was being shown as USD rather than ETH. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23348?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** 1. Open Extension 2. Make note of which preferred currency setting is currently on 3. Verify that if Fiat is toggled on, Fiat appears on top inside the first Token Cell component, and symbols are correct. 4. Verify that if ETH is toggled on, ETH appears on top inside the first Token Cell Component, and symbols are correct. ## **Screenshots/Recordings** ### **Before** Fiat Toggled ON: image image ETH Toggled ON: image image ### **After** Fiat Toggled ON: image image ETH Toggled ON: image image ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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. ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/PR?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 Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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/asset-list/asset-list.js | 21 +++++++++---------- .../__snapshots__/token-cell.test.js.snap | 1 - .../token-list-item.test.js.snap | 1 - .../token-list-item/token-list-item.js | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ui/components/app/asset-list/asset-list.js b/ui/components/app/asset-list/asset-list.js index 7884e28ee0f5..de42660335d4 100644 --- a/ui/components/app/asset-list/asset-list.js +++ b/ui/components/app/asset-list/asset-list.js @@ -90,13 +90,11 @@ const AssetList = ({ onClickAsset }) => { numberOfDecimals: secondaryNumberOfDecimals, } = useUserPreferencedCurrency(SECONDARY, { ethNumberOfDecimals: 4 }); - const [, primaryCurrencyProperties] = useCurrencyDisplay( - selectedAccountBalance, - { + const [primaryCurrencyDisplay, primaryCurrencyProperties] = + useCurrencyDisplay(selectedAccountBalance, { numberOfDecimals: primaryNumberOfDecimals, currency: primaryCurrency, - }, - ); + }); const [secondaryCurrencyDisplay, secondaryCurrencyProperties] = useCurrencyDisplay(selectedAccountBalance, { @@ -190,14 +188,15 @@ const AssetList = ({ onClickAsset }) => { onClickAsset(nativeCurrency)} title={nativeCurrency} + // The primary and secondary currencies are subject to change based on the user's settings + // TODO: rename this primary/secondary concept here to be more intuitive, regardless of setting primary={ - showPrimaryCurrency( + showSecondaryCurrency( isOriginalNativeSymbol, useNativeCurrencyAsPrimaryCurrency, ) - ? primaryCurrencyProperties.value ?? - secondaryCurrencyProperties.value - : null + ? secondaryCurrencyDisplay + : undefined } tokenSymbol={ useNativeCurrencyAsPrimaryCurrency @@ -206,11 +205,11 @@ const AssetList = ({ onClickAsset }) => { } secondary={ showFiat && - showSecondaryCurrency( + showPrimaryCurrency( isOriginalNativeSymbol, useNativeCurrencyAsPrimaryCurrency, ) - ? secondaryCurrencyDisplay + ? primaryCurrencyDisplay : undefined } tokenImage={balanceIsLoading ? null : primaryTokenImage} diff --git a/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap b/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap index ebf7e4a58ccf..04cfdf246020 100644 --- a/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap +++ b/ui/components/app/token-cell/__snapshots__/token-cell.test.js.snap @@ -85,7 +85,6 @@ exports[`Token Cell should match snapshot 1`] = ` 5.000 TEST -

diff --git a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap index c64a5372e1a9..767d276c97e6 100644 --- a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap +++ b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.js.snap @@ -72,7 +72,6 @@ exports[`TokenListItem should render correctly 1`] = ` data-testid="multichain-token-list-item-value" > -

diff --git a/ui/components/multichain/token-list-item/token-list-item.js b/ui/components/multichain/token-list-item/token-list-item.js index d5066208bf13..c7e03331fea0 100644 --- a/ui/components/multichain/token-list-item/token-list-item.js +++ b/ui/components/multichain/token-list-item/token-list-item.js @@ -300,7 +300,7 @@ export const TokenListItem = ({ variant={TextVariant.bodyMd} textAlign={TextAlign.End} > - {primary} {tokenSymbol}{' '} + {primary} {isNativeCurrency ? '' : tokenSymbol} From b5fda83000f8f8c945de88fb05086fa5215361c8 Mon Sep 17 00:00:00 2001 From: Antonio Regadas Date: Wed, 6 Mar 2024 14:04:41 +0000 Subject: [PATCH 30/55] Update changelog for v11.11.2 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a9f241de5ed..55fc0dfda4b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [11.11.2] +### Changed +- Update the image in the Staking button What's New popup ([#23330](https://github.com/MetaMask/metamask-extension/pull/23330)) + +### Fixed +- [MMI] Fixed bug that prevents MMI users from submitting multiple Txs ([#23342](https://github.com/MetaMask/metamask-extension/pull/23342)) +- Fix the display of the native currency token symbol in the asset list + - ([#23355](https://github.com/MetaMask/metamask-extension/pull/23355)) + - ([#23327](https://github.com/MetaMask/metamask-extension/pull/23327)) ## [11.11.1] ### Added From 02dcee52ecaab5a6292b350dcabdc2a244b3aeb9 Mon Sep 17 00:00:00 2001 From: Brian Bergeron Date: Wed, 6 Mar 2024 23:33:38 -0800 Subject: [PATCH 31/55] feat: support bulk balance checks on blast (#23358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support bulk balance checks on blast. This will reduce the number of RPC calls. I deployed this contract to blast to support the feature: https://github.com/wbobeirne/eth-balance-checker This was the tx: https://blastscan.io/tx/0x89a96f29e38ae2c42528ad0b0f07df9465bba6433eda12911c7520bcccc8fbaa Also verified the source code on blastscan. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23358?quickstart=1) Fixes: Switch to blast network, should show native balances correctly across all accounts. - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] 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/constants/contracts.ts | 1 + shared/constants/network.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/scripts/constants/contracts.ts b/app/scripts/constants/contracts.ts index 6cd0acfbe39a..27fa0606dfba 100644 --- a/app/scripts/constants/contracts.ts +++ b/app/scripts/constants/contracts.ts @@ -11,4 +11,5 @@ export const SINGLE_CALL_BALANCES_ADDRESSES = { [CHAIN_IDS.AVALANCHE]: '0xD023D153a0DFa485130ECFdE2FAA7e612EF94818', [CHAIN_IDS.FANTOM]: '0x07f697424ABe762bB808c109860c04eA488ff92B', [CHAIN_IDS.ARBITRUM]: '0x151E24A486D7258dd7C33Fb67E4bB01919B7B32c', + [CHAIN_IDS.BLAST]: '0xfd5730e96f9dffae40d99b77015bd42816280998', }; diff --git a/shared/constants/network.ts b/shared/constants/network.ts index aa6a20fcf3ad..b39a915f925c 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -145,6 +145,7 @@ export const CHAIN_IDS = { GNOSIS: '0x64', ZKSYNC_ERA: '0x144', TEST_ETH: '0x539', + BLAST: '0x13e31', } as const; const CHAINLIST_CHAIN_IDS_MAP = { @@ -852,6 +853,7 @@ export const BUYABLE_CHAINS_MAP: { | typeof CHAIN_IDS.SEPOLIA | typeof CHAIN_IDS.GNOSIS | typeof CHAIN_IDS.AURORA + | typeof CHAIN_IDS.BLAST >]: BuyableChainSettings; } = { [CHAIN_IDS.MAINNET]: { From 61acf0ee4f3970cbe518225bbe0bb88877cbbb02 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 7 Mar 2024 04:08:32 -0330 Subject: [PATCH 32/55] v11.11.3 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55fc0dfda4b9..9eb16b2dc38d 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] +## [11.11.3] + ## [11.11.2] ### Changed - Update the image in the Staking button What's New popup ([#23330](https://github.com/MetaMask/metamask-extension/pull/23330)) @@ -4438,7 +4440,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...HEAD +[11.11.3]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...v11.11.3 [11.11.2]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...v11.11.2 [11.11.1]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...v11.11.1 [11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.1...v11.11.0 diff --git a/package.json b/package.json index 5880b8f6f593..d59fce1f3029 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.11.2", + "version": "11.11.3", "private": true, "repository": { "type": "git", From 98cba32e6726530218e53665250c70517c3c6293 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 7 Mar 2024 17:19:43 -0330 Subject: [PATCH 33/55] v11.11.4 --- CHANGELOG.md | 5 ++++- package.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb16b2dc38d..a775fe6c98e8 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] +## [11.11.4] + ## [11.11.3] ## [11.11.2] @@ -4440,7 +4442,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...HEAD +[11.11.4]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...v11.11.4 [11.11.3]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...v11.11.3 [11.11.2]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...v11.11.2 [11.11.1]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...v11.11.1 diff --git a/package.json b/package.json index d59fce1f3029..e6c19dab3d1e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.11.3", + "version": "11.11.4", "private": true, "repository": { "type": "git", From f09261ebe491a5530577f947daf1f4f48f352dda Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Thu, 7 Mar 2024 22:13:37 +0100 Subject: [PATCH 34/55] fix: cherry-pick snaps hotfix to RC (#23382) ## **Description** Cherry-picks https://github.com/MetaMask/metamask-extension/commit/0c992d9fa1070b5fb77d8c8f293dc1ecce776517 to the RC. --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index dc34aadc5327..e8f94f3609b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4835,14 +4835,14 @@ __metadata: linkType: hard "@metamask/snaps-registry@npm:^3.0.0": - version: 3.0.0 - resolution: "@metamask/snaps-registry@npm:3.0.0" + version: 3.0.1 + resolution: "@metamask/snaps-registry@npm:3.0.1" dependencies: - "@metamask/utils": "npm:^8.1.0" + "@metamask/utils": "npm:^8.3.0" "@noble/curves": "npm:^1.2.0" "@noble/hashes": "npm:^1.3.2" superstruct: "npm:^1.0.3" - checksum: 3c6066807f214cf2cad1dc084b928dcd5b2c98cb09e3e38111ef56ed199f643abb2f035d1a57b7452de197643f6d0b4749541d05764723eb0c6a6f27ae314b06 + checksum: fa981560e13b4ecb077123d7123d7afe9327c06a7f29b71ca760a5e87138738b9e8075f3b9a983231ba5f5df70537eea08e3d2496b7275d649f9337f5a263154 languageName: node linkType: hard From 0f0e25a2c3010a5a90ce1e6027c26d5fb9a01cb9 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Thu, 7 Mar 2024 23:38:38 +0100 Subject: [PATCH 35/55] fix: cherry-pick Snaps feature flag to RC (#23384) ## **Description** Cherry-picks 9ee8738fca4502a6d84a6409013cf11f244d199e to the RC. --- shared/constants/permissions.test.js | 1 - shared/constants/snaps/permissions.ts | 4 +--- test/e2e/run-all.js | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index 99afcaa9208e..bfdd7162e0d7 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -13,7 +13,6 @@ describe('EndowmentPermissions', () => { expect(Object.keys(EndowmentPermissions).sort()).toStrictEqual( [ 'endowment:name-lookup', - 'endowment:page-home', ...Object.keys(endowmentPermissionBuilders).filter( (targetName) => !Object.keys(ExcludedSnapEndowments).includes(targetName), diff --git a/shared/constants/snaps/permissions.ts b/shared/constants/snaps/permissions.ts index 44693e8fa09a..7e222aeedc59 100644 --- a/shared/constants/snaps/permissions.ts +++ b/shared/constants/snaps/permissions.ts @@ -6,8 +6,8 @@ export const EndowmentPermissions = Object.freeze({ 'endowment:rpc': 'endowment:rpc', 'endowment:webassembly': 'endowment:webassembly', 'endowment:lifecycle-hooks': 'endowment:lifecycle-hooks', - ///: BEGIN:ONLY_INCLUDE_IF(build-flask) 'endowment:page-home': 'endowment:page-home', + ///: BEGIN:ONLY_INCLUDE_IF(build-flask) 'endowment:name-lookup': 'endowment:name-lookup', ///: END:ONLY_INCLUDE_IF ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) @@ -25,8 +25,6 @@ export const ExcludedSnapEndowments = Object.freeze({ 'endowment:signature-insight': 'This endowment is in development and therefore not available.', ///: BEGIN:ONLY_INCLUDE_IF(build-main) - 'endowment:page-home': - 'This endowment is experimental and therefore not available.', 'endowment:name-lookup': 'This endowment is experimental and therefore not available.', ///: END:ONLY_INCLUDE_IF diff --git a/test/e2e/run-all.js b/test/e2e/run-all.js index 267305c5eac6..f927756f865a 100644 --- a/test/e2e/run-all.js +++ b/test/e2e/run-all.js @@ -11,7 +11,6 @@ const { loadBuildTypesConfig } = require('../../development/lib/build-type'); const FLASK_ONLY_TESTS = [ 'test-snap-txinsights-v2.spec.js', 'test-snap-namelookup.spec.js', - 'test-snap-homepage.spec.js', ]; const getTestPathsForTestDir = async (testDir) => { From 2602a3b56fe39daf182701802fa6c908f12457c8 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 7 Mar 2024 17:44:24 -0330 Subject: [PATCH 36/55] Update changelog for v11.11.3 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a775fe6c98e8..a49f73347627 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [11.11.4] +### Changed +- Enable Snaps home pages ([#23383](https://github.com/MetaMask/metamask-extension/pull/23383)) + +### Fixed +- Fix intermittent Snaps installation issues due to faulty validation ([#23380](https://github.com/MetaMask/metamask-extension/pull/23380)) ## [11.11.3] From c6401996a39940e748b90d798d83f5227c701769 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Tue, 12 Mar 2024 16:45:54 +0000 Subject: [PATCH 37/55] fix: smart swaps missing chain ID (#23425) --- ui/ducks/swaps/swaps.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/ducks/swaps/swaps.js b/ui/ducks/swaps/swaps.js index 4b0cc084241b..d1f2bae2a40d 100644 --- a/ui/ducks/swaps/swaps.js +++ b/ui/ducks/swaps/swaps.js @@ -996,6 +996,7 @@ export const signAndSendSwapsSmartTransaction = ({ updatedApproveTxParams.gas = `0x${decimalToHex( fees.approvalTxFees?.gasLimit || 0, )}`; + updatedApproveTxParams.chainId = chainId; approvalTxUuid = await dispatch( signAndSendSmartTransaction({ unsignedTransaction: updatedApproveTxParams, @@ -1006,6 +1007,7 @@ export const signAndSendSwapsSmartTransaction = ({ unsignedTransaction.gas = `0x${decimalToHex( fees.tradeTxFees?.gasLimit || 0, )}`; + unsignedTransaction.chainId = chainId; const uuid = await dispatch( signAndSendSmartTransaction({ unsignedTransaction, From c61edf04c14d3648a3b1249183e7d72a556c75b1 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 13 Mar 2024 09:25:48 -0230 Subject: [PATCH 38/55] ci: Update validate-conventional-commits.yml (#23455) Currently we are validating the PR title of PRs made against release branches and master, but this breaks our release branching and PR processes. For release candidate PRs, we don't want a conventional commit title. This PR updates the conventional commit validation workflow. As a result of this PR, we now follow the same approach as mobile https://github.com/MetaMask/metamask-mobile/blob/ef5febdc0964884352486b91b2cfe0e11f3fda29/.github/workflows/pr-title-linter.yml --- .github/workflows/validate-conventional-commits.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/validate-conventional-commits.yml b/.github/workflows/validate-conventional-commits.yml index 922bdddd7db5..aaed4ee1e6ec 100644 --- a/.github/workflows/validate-conventional-commits.yml +++ b/.github/workflows/validate-conventional-commits.yml @@ -1,6 +1,8 @@ name: Validate Conventional Commit Title on: pull_request: + branches: + - develop types: [opened, edited, reopened] jobs: From d4658e11d8d3ddb6d4f0ba6dfd26fc0648f2bdf8 Mon Sep 17 00:00:00 2001 From: Marina Boboc <120041701+benjisclowder@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:23:01 +0200 Subject: [PATCH 39/55] v11.12.0 changelog (#23268) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Adding V11.12.0 changelog. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23268?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 Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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 --- CHANGELOG.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58dde40bc925..ecf05a9cb383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,107 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [11.12.0] +### Added +- Introduced deprecation warnings for Arbitrum Goerli and OP Goerli test networks ([#23071](https://github.com/MetaMask/metamask-extension/pull/23071)) +- Added origin details to personal sign page ([#22763](https://github.com/MetaMask/metamask-extension/pull/22763)) +- Enhanced snap functionality with dynamic interfaces, customizable timeouts, and faster installations ([#22828](https://github.com/MetaMask/metamask-extension/pull/22828)) +- Added a 'Connect Account' button in the account list menu for easier account connections ([#22941](https://github.com/MetaMask/metamask-extension/pull/22941)) +- [FLASK] Added signature insights ([#22485](https://github.com/MetaMask/metamask-extension/pull/22485)) +- [MMI] Enhanced error tracking in MMI controllers ([#22994](https://github.com/MetaMask/metamask-extension/pull/22994)) +- [MMI] Updated MMI dependencies and refactored code ([#22546](https://github.com/MetaMask/metamask-extension/pull/22546)) + +### Changed +- Updated Confirm/Sign button to red for malicious requests ([#23004](https://github.com/MetaMask/metamask-extension/pull/23004)) +- Updated the 'Discover Snaps' link to direct users to snaps.metamask.io ([#22909](https://github.com/MetaMask/metamask-extension/pull/22909)) +- Displayed total account balances on Accounts Menu and home screen ([#22186](https://github.com/MetaMask/metamask-extension/pull/22186)) +- Updated style of app header ([#22637](https://github.com/MetaMask/metamask-extension/pull/22637)) +- Enhanced settings search for better navigation ([#22967](https://github.com/MetaMask/metamask-extension/pull/22967)) +- Enhanced Send Flow by displaying account names during search ([#22824](https://github.com/MetaMask/metamask-extension/pull/22824)) +- Improved send flow by directly showing NFTs tab when sending an NFT ([#23033](https://github.com/MetaMask/metamask-extension/pull/23033)) +- Simplified send flow by removing outdated gas options ([#22951](https://github.com/MetaMask/metamask-extension/pull/22951)) +- [MMI] Improved custodian search by using environment names for unique identification ([#23073](https://github.com/MetaMask/metamask-extension/pull/23073)) +- [MMI] Enhanced MMI keyring configuration for improved mv3 version compatibility ([#22968](https://github.com/MetaMask/metamask-extension/pull/22968)) + +### Fixed +- Improved accuracy of fee details for Optimism transactions ([#22997](https://github.com/MetaMask/metamask-extension/pull/22997)) +- Ensured password prompt appears every time 'Show private key' is selected ([#22867](https://github.com/MetaMask/metamask-extension/pull/22867)) +- Adjusted menu positioning ensuring visibility of all options ([#22889](https://github.com/MetaMask/metamask-extension/pull/22889)) +- Corrected asset list to display native currency symbols instead of fiat on the home page ([#22760](https://github.com/MetaMask/metamask-extension/pull/22760)) +- Fixed tokens being added to incorrect networks after switching networks ([#22814](https://github.com/MetaMask/metamask-extension/pull/22814)) +- Fixed an issue where NFTs disappeared or couldn't be re-imported after account switching ([#22856](https://github.com/MetaMask/metamask-extension/pull/22856)) +- Fixed an issue with saving very low default gas fees ([#22790](https://github.com/MetaMask/metamask-extension/pull/22790)) +- Removed the subtle background behind setting icons ([#22982](https://github.com/MetaMask/metamask-extension/pull/22982)) +- Improved 'See Details' in alerts to stop auto-scrolling ([#22932](https://github.com/MetaMask/metamask-extension/pull/22932)) +- Improved security checks for transactions ([#22978](https://github.com/MetaMask/metamask-extension/pull/22978)) +- Ensured gas fee editing remains accessible even when currency rate checks are disabled ([#22890](https://github.com/MetaMask/metamask-extension/pull/22890)) +- Updated modal overlay for better visibility and focus on content in both light and dark modes ([#23102](https://github.com/MetaMask/metamask-extension/pull/23102)) +- Fixed behavior for manually added networks to show a modal with the option to switch, rather than auto-switching ([#22832](https://github.com/MetaMask/metamask-extension/pull/22832)) +- Corrected link alignment in Snap UI ([#23045](https://github.com/MetaMask/metamask-extension/pull/23045)) +- Resolved an issue that prevented cancelling permission requests without crashing the extension ([#22915](https://github.com/MetaMask/metamask-extension/pull/22915)) +- Fixed badge color in app-header to accurately reflect connection status ([#23126](https://github.com/MetaMask/metamask-extension/pull/23126)) +- Fixed a glitch in the Product Tour where step numbers were not displaying correctly ([#23100](https://github.com/MetaMask/metamask-extension/pull/23100)) +- Enhanced handling of long account names ([#23096](https://github.com/MetaMask/metamask-extension/pull/23096)) +- Resolved issue with tabs overlapping content in the send flow ([#23028](https://github.com/MetaMask/metamask-extension/pull/23028)) +- Ensured consistent balance display in Eth Overview and account list ([#23059](https://github.com/MetaMask/metamask-extension/pull/23059)) +- [MMI] Corrected custody type determination to support various types ([#22950](https://github.com/MetaMask/metamask-extension/pull/22950)) + +## [11.11.4] +### Changed +- Enable Snaps home pages ([#23383](https://github.com/MetaMask/metamask-extension/pull/23383)) + +### Fixed +- Fix intermittent Snaps installation issues due to faulty validation ([#23380](https://github.com/MetaMask/metamask-extension/pull/23380)) + +## [11.11.3] + +## [11.11.2] +### Changed +- Update the image in the Staking button What's New popup ([#23330](https://github.com/MetaMask/metamask-extension/pull/23330)) + +### Fixed +- [MMI] Fixed bug that prevents MMI users from submitting multiple Txs ([#23342](https://github.com/MetaMask/metamask-extension/pull/23342)) +- Fix the display of the native currency token symbol in the asset list + - ([#23355](https://github.com/MetaMask/metamask-extension/pull/23355)) + - ([#23327](https://github.com/MetaMask/metamask-extension/pull/23327)) + +## [11.11.1] +### Added +- Adds a staking button to the mainnet Ethereum token list item ([#22347](https://github.com/MetaMask/metamask-extension/pull/22347)) + +## [11.11.0] +### Added +- Added 'Pet Names' feature, allowing users to see preferred or suggested nicknames in the places of addesses + - Added 'What's New' popup for Petnames feature ([#22780](https://github.com/MetaMask/metamask-extension/pull/22780)) + - Introduced toggle for Petnames in experimental settings ([#22456](https://github.com/MetaMask/metamask-extension/pull/22456)) + - UI enhancements for initial petnames release, including new "Recognized" category and visual refinements ([#22772](https://github.com/MetaMask/metamask-extension/pull/22772)) + - Enhanced token name display with pet names ([#22734](https://github.com/MetaMask/metamask-extension/pull/22734)) +- Added title to Personal Sign component in confirmation design ([#22749](https://github.com/MetaMask/metamask-extension/pull/22749)) +- Added progress indicator for scanning QR codes with hardware wallets ([#20947](https://github.com/MetaMask/metamask-extension/pull/20947)) + +### Changed +- Moved security alerts from Experimental to Security & Privacy settings ([#22813](https://github.com/MetaMask/metamask-extension/pull/22813)) +- Updated BlockaidBannerAlert to support false positive reporting for failed types ([#22742](https://github.com/MetaMask/metamask-extension/pull/22742)) +- Enhanced BlockaidBannerAlert functionality and display ([#22625](https://github.com/MetaMask/metamask-extension/pull/22625)) +- Disabled smart swaps for Snap accounts ([#22731](https://github.com/MetaMask/metamask-extension/pull/22731)) +- Disabled MetaMask on Battle.net to fix a 2FA login issue ([#20396](https://github.com/MetaMask/metamask-extension/pull/20396)) +- Revised warning copy for mismatched chainID and currency symbol when adding custom networks ([#22648](https://github.com/MetaMask/metamask-extension/pull/22648)) +- Improved UX to display multiple custom networks with the same ID but different RPC URLs in network selection ([#22693](https://github.com/MetaMask/metamask-extension/pull/22693)) +- Updated the connections icon to display the connected dapp icon ([#22634](https://github.com/MetaMask/metamask-extension/pull/22634)) +- Added title to Personal Sign page ([#22749](https://github.com/MetaMask/metamask-extension/pull/22749)) +- Update padding in accounts details modal ([#22775](https://github.com/MetaMask/metamask-extension/pull/22775)) +- [MMI] Refactored display of custodian deep link to improve efficiency and fix potential race conditions ([#22825](https://github.com/MetaMask/metamask-extension/pull/22825)) +- [MMI] Hid the new buy & receive button under MMI build for a cleaner interface ([#22384](https://github.com/MetaMask/metamask-extension/pull/22384)) + +### Fixed +- Fixed cancel transaction signing from activity list ([#22676](https://github.com/MetaMask/metamask-extension/pull/22676)) +- Fixed incorrect account name display in account details and receive list ([#22844](https://github.com/MetaMask/metamask-extension/pull/22844)) +- Fixed IPFS NFTs fetching issue for manually imported NFTs ([#22627](https://github.com/MetaMask/metamask-extension/pull/22627)) +- Fixed "send max" ETH calculation issue to adjust for gas changes ([#22694](https://github.com/MetaMask/metamask-extension/pull/22694)) +- Fixed sign button color and updated deprecated components in SignatureRequestOriginalWarning for visual consistency ([#22741](https://github.com/MetaMask/metamask-extension/pull/22741)) + +## [11.10.1] +### Fixed +- Fix custom network editing, via Settings, for some networks ([#23140](https://github.com/MetaMask/metamask-extension/pull/23140)) ## [11.10.0] ### Added @@ -4393,6 +4494,13 @@ Update styles and spacing on the critical error page ([#20350](https://github.c [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...HEAD [11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.12.0 +[11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...v11.12.0 +[11.11.4]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...v11.11.4 +[11.11.3]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...v11.11.3 +[11.11.2]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...v11.11.2 +[11.11.1]: https://github.com/MetaMask/metamask-extension/compare/v11.11.0...v11.11.1 +[11.11.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.1...v11.11.0 +[11.10.1]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.10.1 [11.10.0]: https://github.com/MetaMask/metamask-extension/compare/v11.9.5...v11.10.0 [11.9.5]: https://github.com/MetaMask/metamask-extension/compare/v11.9.4...v11.9.5 [11.9.4]: https://github.com/MetaMask/metamask-extension/compare/v11.9.3...v11.9.4 From 9faeedef6fcc24fe7fe62d916d9743bd458074d0 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Fri, 23 Feb 2024 21:07:28 +0900 Subject: [PATCH 40/55] fix(deps): socks@2.8.0->2.8.1 (#23143) --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index f9d7ad9d1f14..53cadda9b287 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31555,12 +31555,12 @@ __metadata: linkType: hard "socks@npm:^2.6.1, socks@npm:^2.6.2, socks@npm:^2.7.1": - version: 2.8.0 - resolution: "socks@npm:2.8.0" + version: 2.8.1 + resolution: "socks@npm:2.8.1" dependencies: ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: ed0224ce2c7daaa7690cb87cf53d9703ffc4e983aca221f6f5b46767b232658df49494fd86acd0bf97ada6de05248ea8ea625c2343d48155d8463fc40d4a340f + checksum: a3cc38e0716ab53a2db3fa00c703ca682ad54dbbc9ed4c7461624a999be6fa7cdc79fc904c411618e698d5eff55a55aa6d9329169a7db11636d0200814a2b5aa languageName: node linkType: hard From 41430d4cdfa92213f53c4dc5dd148a0715b12ad3 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 13 Mar 2024 15:45:19 -0230 Subject: [PATCH 41/55] Changelog lint for v11.12.0 --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fee6ba51c47e..49cc5a5364d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4493,9 +4493,7 @@ 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/v11.12.0...HEAD -[11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.10.0...v11.12.0 [11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...v11.12.0 -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...HEAD [11.11.4]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...v11.11.4 [11.11.3]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...v11.11.3 [11.11.2]: https://github.com/MetaMask/metamask-extension/compare/v11.11.1...v11.11.2 From 41b58b966ed4f1588b91f5be3ff54fc5471293ba Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 13 Mar 2024 16:03:42 -0230 Subject: [PATCH 42/55] Fix merge conflict error after merging master v11.11.x to v11.12.0 --- .../blockaid-banner-alert.test.js.snap | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap index bedf452a9e79..a79334ddc1cc 100644 --- a/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap +++ b/ui/pages/confirmations/components/security-provider-banner-alert/blockaid-banner-alert/__snapshots__/blockaid-banner-alert.test.js.snap @@ -51,11 +51,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo Something doesn't look right? >>>>>> master rel="noopener noreferrer" target="_blank" > @@ -148,11 +144,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? >>>>>> master rel="noopener noreferrer" target="_blank" > @@ -245,11 +237,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp Something doesn't look right? >>>>>> master rel="noopener noreferrer" target="_blank" > @@ -343,11 +331,7 @@ exports[`Blockaid Banner Alert should render details section even when features Something doesn't look right? >>>>>> master rel="noopener noreferrer" target="_blank" > @@ -454,11 +438,7 @@ exports[`Blockaid Banner Alert should render details when provided 1`] = ` Something doesn't look right? >>>>>> master rel="noopener noreferrer" target="_blank" > @@ -553,11 +533,7 @@ exports[`Blockaid Banner Alert should render link to report url 1`] = ` Something doesn't look right? >>>>>> master rel="noopener noreferrer" target="_blank" > From bb087b78918fef8839eb558b7b532bb9817f23da Mon Sep 17 00:00:00 2001 From: Chloe Gao Date: Thu, 14 Mar 2024 15:31:07 +0100 Subject: [PATCH 43/55] v11.12.1 --- CHANGELOG.md | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cc5a5364d6..d9503370954e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.12.1] +### Changed +- Updated styling for missing petnames to prevent misinterpretation as malicious ([#23458](https://github.com/MetaMask/metamask-extension/pull/23458)) + ## [11.12.0] ### Added - Introduced deprecation warnings for Arbitrum Goerli and OP Goerli test networks ([#23071](https://github.com/MetaMask/metamask-extension/pull/23071)) @@ -4492,7 +4496,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.1...HEAD +[11.12.1]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...v11.12.1 [11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...v11.12.0 [11.11.4]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...v11.11.4 [11.11.3]: https://github.com/MetaMask/metamask-extension/compare/v11.11.2...v11.11.3 diff --git a/package.json b/package.json index 80cd06bfaa7a..b9fbd226cb8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.12.0", + "version": "11.12.1", "private": true, "repository": { "type": "git", From 5480be43d824a22e87ae218242b324d199aa246c Mon Sep 17 00:00:00 2001 From: chloeYue <105063779+chloeYue@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:43:17 +0100 Subject: [PATCH 44/55] cherry-pick feat: update style of missing petnames (#23490) ## **Description** Cherry-pick #23458 in hotfix v11.12.1 Co-authored-by: Matthew Walsh --- ui/components/app/name/index.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/components/app/name/index.scss b/ui/components/app/name/index.scss index afbfd40df00b..4c38c5f76806 100644 --- a/ui/components/app/name/index.scss +++ b/ui/components/app/name/index.scss @@ -8,10 +8,10 @@ max-width: 100%; &__missing { - background-color: var(--color-error-muted); + background-color: var(--color-background-alternative); .name__value { - color: var(--color-error-default); + color: var(--color-text-default); } } @@ -32,7 +32,7 @@ } &__missing &__icon { - color: var(--color-error-default); + color: var(--color-text-default); } &__saved &__icon { From 5478b5c29433c55fe9803ed189ad4c85e5993f38 Mon Sep 17 00:00:00 2001 From: Olusegun Akintayo Date: Thu, 29 Feb 2024 16:21:22 +0300 Subject: [PATCH 45/55] fix: Transaction Confirmation incorrectly showing max instead of estimated fees and total (#23203) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The Transaction Confirmation screen is incorrectly showing max fees and totals where estimated values should be: We should show the estimated and max fee and total independently: [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23203?quickstart=1) ## **Related issues** Fixes: [#2112](https://github.com/MetaMask/MetaMask-planning/issues/2112) ## **Manual testing steps** 1. Launch MM 2. Perform a send transaction 3. See how the Estimate fees and max fees are the same 4. Checkout this branch 5. Build and launch MM 6. Perform a send transaction 7. See how the estimate fees and max fees are not the same and estimate is less than max ## **Screenshots/Recordings** ### **Before** https://github.com/MetaMask/metamask-extension/assets/44811/9f553918-e56b-4a01-a119-7c67ff1593ca ### **After** https://github.com/MetaMask/metamask-extension/assets/44811/883e808b-a85f-43fe-a03a-6df9556b66d3 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [ ] 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. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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. --- .../__snapshots__/confirm-gas-display.test.js.snap | 8 ++++---- .../gas-details-item/gas-details-item.js | 14 ++++++++++++-- .../confirm-transaction-base.component.js | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap b/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap index e4b206933e3d..99e089514026 100644 --- a/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap +++ b/ui/pages/confirmations/components/confirm-gas-display/__snapshots__/confirm-gas-display.test.js.snap @@ -42,12 +42,12 @@ exports[`ConfirmGasDisplay should match snapshot 1`] = `
- 0.00147 + 0.001197
@@ -60,12 +60,12 @@ exports[`ConfirmGasDisplay should match snapshot 1`] = ` >
- 0.00147 + 0.001197 { + if (isMultiLayerFeeNetwork) { + return sumHexes(hexMinimumTransactionFee, estimatedL1Fees || 0); + } + + return hexMinimumTransactionFee; + }, [isMultiLayerFeeNetwork, hexMinimumTransactionFee, estimatedL1Fees]); + + const getMaxTransactionFeeTotal = useMemo(() => { if (isMultiLayerFeeNetwork) { return sumHexes(hexMaximumTransactionFee, estimatedL1Fees || 0); } @@ -156,7 +164,9 @@ const GasDetailsItem = ({
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 5c735a0f8e93..ec4b68217fa6 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 @@ -537,7 +537,7 @@ export default class ConfirmTransactionBase extends Component { detailText={ useCurrencyRateCheck && renderTotalDetailText(getTotalAmount()) } - detailTotal={renderTotalMaxAmount(true)} + detailTotal={renderTotalMaxAmount(false)} subTitle={t('transactionDetailGasTotalSubtitle')} subText={
From 16a12080e4a05e7401162ea03c679cc75bfe912b Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Fri, 15 Mar 2024 07:56:36 -0230 Subject: [PATCH 46/55] fix: Fix confirmation tx totals on layer 2 networks and for erc20 transfers (#23511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** While testing https://github.com/MetaMask/metamask-extension/pull/23510, I discovered that total fees had some inaccuracies in two cases: 1. On OP layer 2 networks, the rendered total on the confirmation screen was not including the estimated layer 1 fees (as it does in the 'Estimated Fees' section) 2. For confirmations of the ERC20 transfers, the rendered total that is supposed to be ERC20 token + estimated fee was actually ERC20 token + maximum fee. The fix for 1 was to bring in fetching of layer1 multi-network fee data into the confirmation-transaction-base component. The fix for 2 is just to make sure that when we are rendering the transaction detail line where `useMax` is false, we choose the correct token fee to render (see the new `primaryFee` variable introduced in this PR). These two fixes are included in separate commits ### **Before: Layer 2 total fees** ![Screenshot from 2024-03-14 22-43-28](https://github.com/MetaMask/metamask-extension/assets/7499938/1d80ba80-3e54-4a94-97e6-daa0f17b8fd7) ### **After: Layer 2 total fees** ![Screenshot from 2024-03-14 23-46-02](https://github.com/MetaMask/metamask-extension/assets/7499938/3fe61964-df99-4c46-af3c-c49aaf9f0c0f) ### **Before: ERC20 sends** ![Screenshot from 2024-03-14 23-59-29](https://github.com/MetaMask/metamask-extension/assets/7499938/e132e060-92c5-4a69-84e9-8fb6c7da2d99) ### **After: ERC20 sends** ![Screenshot from 2024-03-15 00-15-03](https://github.com/MetaMask/metamask-extension/assets/7499938/4d25dca9-c493-478a-84ce-c3b04b1c7a58) ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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 | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) 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 ec4b68217fa6..5ff6bd63e59c 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 @@ -7,6 +7,8 @@ import { import ConfirmPageContainer from '../components/confirm-page-container'; import { isBalanceSufficient } from '../send/send.utils'; import { DEFAULT_ROUTE } from '../../../helpers/constants/routes'; +import fetchEstimatedL1Fee from '../../../helpers/utils/optimism/fetchEstimatedL1Fee'; + import { INSUFFICIENT_FUNDS_ERROR_KEY, GAS_LIMIT_TOO_LOW_ERROR_KEY, @@ -47,7 +49,7 @@ import { MIN_GAS_LIMIT_DEC } from '../send/send.constants'; import { NETWORK_TO_NAME_MAP } from '../../../../shared/constants/network'; import { - addHexes, + sumHexes, hexToDecimal, } from '../../../../shared/modules/conversion.utils'; import TransactionAlerts from '../components/transaction-alerts'; @@ -159,6 +161,7 @@ export default class ConfirmTransactionBase extends Component { isUserOpContractDeployError: PropTypes.bool, useMaxValue: PropTypes.bool, maxValue: PropTypes.string, + isMultiLayerFeeNetwork: PropTypes.bool, }; state = { @@ -169,6 +172,7 @@ export default class ConfirmTransactionBase extends Component { editingGas: false, userAcknowledgedGasMissing: false, showWarningModal: false, + estimatedL1Fees: 0, ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) noteText: '', ///: END:ONLY_INCLUDE_IF @@ -188,6 +192,7 @@ export default class ConfirmTransactionBase extends Component { setDefaultHomeActiveTabName, hexMaximumTransactionFee, useMaxValue, + txData, } = this.props; const { customNonceValue: prevCustomNonceValue, @@ -242,11 +247,21 @@ export default class ConfirmTransactionBase extends Component { } } - if ( - hexMaximumTransactionFee !== prevHexMaximumTransactionFee && - useMaxValue - ) { - this.updateValueToMax(); + if (hexMaximumTransactionFee !== prevHexMaximumTransactionFee) { + fetchEstimatedL1Fee(txData?.chainId, txData) + .then((result) => { + this.setState({ + estimatedL1Fees: result, + }); + }) + .catch((_err) => { + this.setState({ + estimatedL1Fees: 0, + }); + }); + if (useMaxValue) { + this.updateValueToMax(); + } } } @@ -377,10 +392,11 @@ export default class ConfirmTransactionBase extends Component { useCurrencyRateCheck, tokenSymbol, isUsingPaymaster, + isMultiLayerFeeNetwork, } = this.props; const { t } = this.context; - const { userAcknowledgedGasMissing } = this.state; + const { userAcknowledgedGasMissing, estimatedL1Fees } = this.state; const { valid } = this.getErrorKey(); const isDisabled = () => { @@ -394,9 +410,10 @@ export default class ConfirmTransactionBase extends Component { const networkName = NETWORK_TO_NAME_MAP[txData.chainId]; const getTotalAmount = (useMaxFee) => { - return addHexes( + return sumHexes( txData.txParams.value, useMaxFee ? hexMaximumTransactionFee : hexMinimumTransactionFee, + isMultiLayerFeeNetwork ? estimatedL1Fees : 0, ); }; @@ -417,8 +434,11 @@ export default class ConfirmTransactionBase extends Component { } // Token send - return useNativeCurrencyAsPrimaryCurrency + const primaryTotal = useMaxFee ? primaryTotalTextOverrideMaxAmount + : primaryTotalTextOverride; + return useNativeCurrencyAsPrimaryCurrency + ? primaryTotal : secondaryTotalTextOverride; }; From 7d36bbf3fd0227321a6a5758538e7fbe27044c18 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 14 Mar 2024 22:02:55 -0230 Subject: [PATCH 47/55] v11.12.2 --- CHANGELOG.md | 9 ++++++++- package.json | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9503370954e..da035b6c047d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.12.2] +### Fixed +- Fix transaction confirmations so that they correctly show estimated fees instead of max possible fees + - For non-layer 2 network, and non-token send, transactions([#23203](https://github.com/MetaMask/metamask-extension/pull/23203)) + - For layer 2 networks and for erc20 transfers ([#23511](https://github.com/MetaMask/metamask-extension/pull/23511)) + ## [11.12.1] ### Changed - Updated styling for missing petnames to prevent misinterpretation as malicious ([#23458](https://github.com/MetaMask/metamask-extension/pull/23458)) @@ -4496,7 +4502,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.1...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.2...HEAD +[11.12.2]: https://github.com/MetaMask/metamask-extension/compare/v11.12.1...v11.12.2 [11.12.1]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...v11.12.1 [11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...v11.12.0 [11.11.4]: https://github.com/MetaMask/metamask-extension/compare/v11.11.3...v11.11.4 diff --git a/package.json b/package.json index b9fbd226cb8b..749d7272c51b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.12.1", + "version": "11.12.2", "private": true, "repository": { "type": "git", From 339f24a76dad67b5b667d6f1aa10141c67c312ee Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Fri, 15 Mar 2024 23:47:27 +0530 Subject: [PATCH 48/55] fix: Gas display fixes on confirmation screen (#23524) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR corrects the display of the "Total" value under the "Fee Details" dropdown. It also ensures the "Fee details" dropdown is only shown on layer 2 networks. This is the correct spec, as confirmed with @bschorchit Fixes: https://github.com/MetaMask/metamask-extension/issues/23515 1. On eth mainnet, create a transaction 2. There should be no "Fee details" dropdown, and other fee information should be correct. 1. On Optimism, create a transaction 2. Their should be a fee details, and opening it should show a Total that matches the estimated total shown below/outside the "fee details" section Layer 1 ![Screenshot from 2024-03-15 14-08-03](https://github.com/MetaMask/metamask-extension/assets/7499938/ed348930-14db-4818-b207-9f3fa2c09ff6) Layer 2 ![Screenshot from 2024-03-15 14-07-10](https://github.com/MetaMask/metamask-extension/assets/7499938/bb879810-87bc-42cc-9bf5-4860aa6e5b75) Layer 1 ![Screenshot from 2024-03-15 14-09-44](https://github.com/MetaMask/metamask-extension/assets/7499938/cce1d206-088c-4b60-889c-ed467e53b535) Layer 2 ![Screenshot from 2024-03-15 13-59-02](https://github.com/MetaMask/metamask-extension/assets/7499938/e8d41718-e10a-4f3e-873c-e55a64bed8b9) - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] 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 --- .../fee-details-component.js | 13 +-- .../fee-details-component.test.js | 50 +++++++-- ...irm-approve-content.component.test.js.snap | 104 +----------------- .../confirm-send-ether.test.js.snap | 26 +---- .../confirm-transaction-base.test.js.snap | 26 +---- 5 files changed, 51 insertions(+), 168 deletions(-) diff --git a/ui/pages/confirmations/components/fee-details-component/fee-details-component.js b/ui/pages/confirmations/components/fee-details-component/fee-details-component.js index b329d6704951..0c84336bed3e 100644 --- a/ui/pages/confirmations/components/fee-details-component/fee-details-component.js +++ b/ui/pages/confirmations/components/fee-details-component/fee-details-component.js @@ -43,10 +43,7 @@ export default function FeeDetailsComponent({ const t = useI18nContext(); - const { - maximumCostInHexWei: hexMaximumTransactionFee, - minimumCostInHexWei: hexMinimumTransactionFee, - } = useGasFeeContext(); + const { minimumCostInHexWei: hexMinimumTransactionFee } = useGasFeeContext(); useEffect(() => { if (isMultiLayerFeeNetwork) { fetchEstimatedL1Fee(txData?.chainId, txData) @@ -61,11 +58,11 @@ export default function FeeDetailsComponent({ const getTransactionFeeTotal = useMemo(() => { if (isMultiLayerFeeNetwork) { - return addHexes(hexMaximumTransactionFee, estimatedL1Fees || 0); + return addHexes(hexMinimumTransactionFee, estimatedL1Fees || 0); } - return hexMaximumTransactionFee; - }, [isMultiLayerFeeNetwork, hexMaximumTransactionFee, estimatedL1Fees]); + return hexMinimumTransactionFee; + }, [isMultiLayerFeeNetwork, hexMinimumTransactionFee, estimatedL1Fees]); const renderTotalDetailText = useCallback( (value) => { @@ -109,7 +106,7 @@ export default function FeeDetailsComponent({ justifyContent={JustifyContent.center} flexDirection={FlexDirection.Column} > - {!hideGasDetails && ( + {!hideGasDetails && isMultiLayerFeeNetwork && ( { }; describe('FeeDetailsComponent', () => { - it('renders "Fee details"', () => { - render(); + it('renders "Fee details"', async () => { + await render({ + ...mockState, + metamask: { + ...mockState.metamask, + providerConfig: { + chainId: CHAIN_IDS.OPTIMISM, + }, + }, + }); expect(screen.queryByText('Fee details')).toBeInTheDocument(); }); - it('should expand when button is clicked', () => { - render(); + it('should expand when button is clicked', async () => { + await render({ + ...mockState, + metamask: { + ...mockState.metamask, + providerConfig: { + chainId: CHAIN_IDS.OPTIMISM, + }, + }, + }); expect(screen.queryByTitle('0 ETH')).not.toBeInTheDocument(); - screen.getByRole('button').click(); - expect(screen.queryByTitle('0 ETH')).toBeInTheDocument(); + await act(async () => { + screen.getByRole('button').click(); + }); + expect(screen.getAllByTitle('0 ETH')).toHaveLength(2); + expect(screen.getAllByTitle('0 ETH')[0]).toBeInTheDocument(); }); - it('should be displayed for even legacy network', () => { - render({ + it('should be displayed for layer 2 network', async () => { + await render({ ...mockState, metamask: { ...mockState.metamask, @@ -41,6 +60,17 @@ describe('FeeDetailsComponent', () => { 1559: false, }, }, + networksMetadata: { + goerli: { + EIPS: { + 1559: false, + }, + status: 'available', + }, + }, + providerConfig: { + chainId: CHAIN_IDS.OPTIMISM, + }, }, }); expect(screen.queryByText('Fee details')).toBeInTheDocument(); diff --git a/ui/pages/confirmations/confirm-approve/confirm-approve-content/__snapshots__/confirm-approve-content.component.test.js.snap b/ui/pages/confirmations/confirm-approve/confirm-approve-content/__snapshots__/confirm-approve-content.component.test.js.snap index 84374e307205..a4bd02de6c35 100644 --- a/ui/pages/confirmations/confirm-approve/confirm-approve-content/__snapshots__/confirm-approve-content.component.test.js.snap +++ b/ui/pages/confirmations/confirm-approve/confirm-approve-content/__snapshots__/confirm-approve-content.component.test.js.snap @@ -115,31 +115,7 @@ exports[`ConfirmApproveContent Component should render Confirm approve page corr >
-
- -
-
+ />
-
- -
-
+ />
-
- -
-
+ />
-
- -
-
+ />
-
- -
-
+ />
diff --git a/ui/pages/confirmations/confirm-transaction-base/__snapshots__/confirm-transaction-base.test.js.snap b/ui/pages/confirmations/confirm-transaction-base/__snapshots__/confirm-transaction-base.test.js.snap index 2f64281591fc..6fde90864dde 100644 --- a/ui/pages/confirmations/confirm-transaction-base/__snapshots__/confirm-transaction-base.test.js.snap +++ b/ui/pages/confirmations/confirm-transaction-base/__snapshots__/confirm-transaction-base.test.js.snap @@ -405,31 +405,7 @@ exports[`Confirm Transaction Base should match snapshot 1`] = `
-
- -
-
+ /> From f604c737358cbc142c85205ce68fa3518d748b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Fri, 15 Mar 2024 10:58:52 +0000 Subject: [PATCH 49/55] chore: MMI adds fallback property when environment key doesnt exist (#23494) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We need to add the `service` key value as a fallback for when the custodian doesn't send an `environment` property. ## **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 Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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-add-custodian-token.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.js b/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.js index 90b058bc77d1..27a1edd94cea 100644 --- a/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.js +++ b/ui/pages/institutional/confirm-add-custodian-token/confirm-add-custodian-token.js @@ -125,8 +125,10 @@ const ConfirmAddCustodianToken = () => { const custodianLabel = connectRequest.labels?.find((label) => label.key === 'service')?.value || t('custodian'); + + // Some custodians dont sent the "environment" inthe connect request const custodian = findCustodianByEnvName( - connectRequest.environment, + connectRequest.environment || custodianLabel, custodians, ); From ae36b1675e20a3159e2dcd9f1164e29e08108756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Mon, 18 Mar 2024 12:24:10 +0000 Subject: [PATCH 50/55] chore: adds a needed code fence and blockaid to MMI build (#23516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** In MMI build we currently don't have `blockaid` in our features (builds.yml), so this caused a bug, addressed now by this PR. The problem is that the `appStateController` being used inside `app/scripts/lib/createRPCMethodTrackingMiddleware.js `is not code fenced. https://github.com/MetaMask/metamask-extension/blob/b5fda83000f8f8c945de88fb05086fa5215361c8/app/scripts/lib/createRPCMethodTrackingMiddleware.js#L322 It's being passed in `metamask-controller` protected by the code fence: https://github.com/MetaMask/metamask-extension/blob/b5fda83000f8f8c945de88fb05086fa5215361c8/app/scripts/metamask-controller.js#L4728 But inside the createRPCMethodTrackingMiddleware it's being used without the `blockaid` code fence, so in our case since we didn't have `blockaid` added in the yml to our build type, the `appStateController` would always be undefined. This was introduced in this PR https://github.com/MetaMask/metamask-extension/pull/22874/files and the [author mentioned](https://github.com/MetaMask/metamask-extension/pull/22874/files#r1483023840) that it should be code fenced, but never did btw. ## **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 Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] 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 properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **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: MetaMask Bot --- .../lib/createRPCMethodTrackingMiddleware.js | 2 ++ builds.yml | 1 + lavamoat/browserify/mmi/policy.json | 34 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/app/scripts/lib/createRPCMethodTrackingMiddleware.js b/app/scripts/lib/createRPCMethodTrackingMiddleware.js index 02bbb7c55df8..933e81e7df09 100644 --- a/app/scripts/lib/createRPCMethodTrackingMiddleware.js +++ b/app/scripts/lib/createRPCMethodTrackingMiddleware.js @@ -325,6 +325,7 @@ export default function createRPCMethodTrackingMiddleware({ let blockaidMetricProps = {}; + ///: BEGIN:ONLY_INCLUDE_IF(blockaid) if (!isDisabledRPCMethod) { if (SIGNING_METHODS.includes(method)) { const securityAlertResponse = @@ -337,6 +338,7 @@ export default function createRPCMethodTrackingMiddleware({ }); } } + ///: END:ONLY_INCLUDE_IF const properties = { ...eventProperties, diff --git a/builds.yml b/builds.yml index 3d282460eebd..daf251bd0a77 100644 --- a/builds.yml +++ b/builds.yml @@ -100,6 +100,7 @@ buildTypes: features: - build-mmi - snaps + - blockaid env: - INFURA_MMI_PROJECT_ID - SEGMENT_MMI_WRITE_KEY diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 6cd1fa3f0130..f78f3c0c5772 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1827,6 +1827,40 @@ "webpack>events": true } }, + "@metamask/ppom-validator": { + "globals": { + "URL": true, + "console.error": true, + "crypto": true + }, + "packages": { + "@metamask/controller-utils": true, + "@metamask/eth-query>json-rpc-random-id": true, + "@metamask/ppom-validator>@metamask/base-controller": true, + "@metamask/ppom-validator>crypto-js": true, + "@metamask/ppom-validator>elliptic": true, + "await-semaphore": true, + "browserify>buffer": true + } + }, + "@metamask/ppom-validator>@metamask/base-controller": { + "globals": { + "setTimeout": true + }, + "packages": { + "immer": true + } + }, + "@metamask/ppom-validator>crypto-js": { + "globals": { + "crypto": true, + "define": true, + "msCrypto": true + }, + "packages": { + "browserify>browser-resolve": true + } + }, "@metamask/ppom-validator>elliptic": { "packages": { "@metamask/ppom-validator>elliptic>brorand": true, From 55f21f7e6b4cf217cf2cf50a89993d5866201167 Mon Sep 17 00:00:00 2001 From: Antonio Regadas Date: Mon, 18 Mar 2024 12:38:04 +0000 Subject: [PATCH 51/55] chore: updates changelog and package json --- CHANGELOG.md | 8 +++++++- package.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da035b6c047d..e8a819529166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.12.3] +### Fixed +- [MMI] Fixes an error related with a missing code fence, when the MMI build didn't have the blockaid feature ([#23516](https://github.com/MetaMask/metamask-extension/pull/23516)) +- [MMI] Fixes a bug for some custodians that don't send us the env property when connection to MMI ([#23494](https://github.com/MetaMask/metamask-extension/pull/23494)) + ## [11.12.2] ### Fixed - Fix transaction confirmations so that they correctly show estimated fees instead of max possible fees @@ -4502,7 +4507,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.2...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.3...HEAD +[11.12.3]: https://github.com/MetaMask/metamask-extension/compare/v11.12.2...v11.12.3 [11.12.2]: https://github.com/MetaMask/metamask-extension/compare/v11.12.1...v11.12.2 [11.12.1]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...v11.12.1 [11.12.0]: https://github.com/MetaMask/metamask-extension/compare/v11.11.4...v11.12.0 diff --git a/package.json b/package.json index 749d7272c51b..2524da7ba8b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.12.2", + "version": "11.12.3", "private": true, "repository": { "type": "git", From a76ae4a9d3956abb35cdef09c71beb388fc0f73b Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 20 Mar 2024 17:14:39 -0230 Subject: [PATCH 52/55] v11.12.4 --- CHANGELOG.md | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8a819529166..6d6d191fc49d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [11.12.4] +### Fixed +- Ensure native network balance is visible in home screen balance display ([#23614](https://github.com/MetaMask/metamask-extension/pull/23614)) + ## [11.12.3] ### Fixed - [MMI] Fixes an error related with a missing code fence, when the MMI build didn't have the blockaid feature ([#23516](https://github.com/MetaMask/metamask-extension/pull/23516)) @@ -4507,7 +4511,8 @@ Update styles and spacing on the critical error page ([#20350](https://github.c ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.3...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.12.4...HEAD +[11.12.4]: https://github.com/MetaMask/metamask-extension/compare/v11.12.3...v11.12.4 [11.12.3]: https://github.com/MetaMask/metamask-extension/compare/v11.12.2...v11.12.3 [11.12.2]: https://github.com/MetaMask/metamask-extension/compare/v11.12.1...v11.12.2 [11.12.1]: https://github.com/MetaMask/metamask-extension/compare/v11.12.0...v11.12.1 diff --git a/package.json b/package.json index 2524da7ba8b7..dee4ac170e3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "11.12.3", + "version": "11.12.4", "private": true, "repository": { "type": "git", From 177ec59564bb3ee3ea85e42a8430057cf54befb8 Mon Sep 17 00:00:00 2001 From: Brian Bergeron Date: Wed, 20 Mar 2024 13:37:25 -0700 Subject: [PATCH 53/55] fix: revert aggregated fiat balance on home page (#23614) (#23617) cherry picking https://github.com/MetaMask/metamask-extension/pull/23614 Not a clean cherry pick, handled conflicts in 3 files. --------- Co-authored-by: Dan J Miller --- test/e2e/helpers.js | 9 +--- test/e2e/tests/account-token-list.spec.js | 2 +- test/e2e/tests/contract-interactions.spec.js | 9 ++-- test/e2e/tests/incremental-security.spec.js | 8 +-- test/e2e/tests/localization.spec.js | 2 +- test/e2e/tests/lock-account.spec.js | 2 +- test/e2e/tests/metamask-responsive-ui.spec.js | 4 +- test/e2e/tests/migrate-old-vault.spec.js | 2 +- test/e2e/tests/send-eth.spec.js | 16 +++--- .../app/wallet-overview/eth-overview.js | 49 +++++++------------ .../app/wallet-overview/eth-overview.test.js | 4 +- 11 files changed, 42 insertions(+), 65 deletions(-) diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 210790844a50..dcc693b4a855 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -808,16 +808,11 @@ const TEST_SEED_PHRASE_TWO = // Usually happens when onboarded to make sure the state is retrieved from metamaskState properly, or after txn is made const locateAccountBalanceDOM = async (driver, ganacheServer) => { - const balance = (await ganacheServer.getFiatBalance()).toLocaleString( - undefined, - { - minimumFractionDigits: 2, - }, - ); + const balance = await ganacheServer.getBalance(); await driver.findElement({ css: '[data-testid="eth-overview__primary-currency"]', - text: `$ ${balance} USD`, + text: `${balance} ETH`, }); }; diff --git a/test/e2e/tests/account-token-list.spec.js b/test/e2e/tests/account-token-list.spec.js index c92e1217de4f..f0f08ae8fcdb 100644 --- a/test/e2e/tests/account-token-list.spec.js +++ b/test/e2e/tests/account-token-list.spec.js @@ -65,7 +65,7 @@ describe('Settings', function () { const tokenListAmount = await driver.findElement( '.eth-overview__primary-container', ); - assert.equal(await tokenListAmount.getText(), '$42,500.00\nUSD'); + assert.equal(await tokenListAmount.getText(), '25\nETH'); await driver.clickElement('[data-testid="account-menu-icon"]'); const accountTokenValue = await driver.waitForSelector( '.multichain-account-list-item .multichain-account-list-item__asset', diff --git a/test/e2e/tests/contract-interactions.spec.js b/test/e2e/tests/contract-interactions.spec.js index 3f87e112a21e..d59ece2d97ed 100644 --- a/test/e2e/tests/contract-interactions.spec.js +++ b/test/e2e/tests/contract-interactions.spec.js @@ -1,4 +1,3 @@ -const { strict: assert } = require('assert'); const { defaultGanacheOptions, withFixtures, @@ -6,6 +5,7 @@ const { unlockWallet, largeDelayMs, WINDOW_TITLES, + locateAccountBalanceDOM, } = require('../helpers'); const { SMART_CONTRACTS } = require('../seeder/smart-contracts'); @@ -25,7 +25,7 @@ describe('Deploy contract and call contract methods', function () { smartContract, title: this.test.fullTitle(), }, - async ({ driver, contractRegistry }) => { + async ({ driver, contractRegistry, ganacheServer }) => { const contractAddress = await contractRegistry.getContractAddress( smartContract, ); @@ -87,10 +87,7 @@ describe('Deploy contract and call contract methods', function () { await driver.switchToWindowWithTitle( WINDOW_TITLES.ExtensionInFullScreenView, ); - const balance = await driver.findElement( - '[data-testid="eth-overview__primary-currency"]', - ); - assert.equal(await balance.getText(), '$37,399.05\nUSD'); + await locateAccountBalanceDOM(driver, ganacheServer); }, ); }); diff --git a/test/e2e/tests/incremental-security.spec.js b/test/e2e/tests/incremental-security.spec.js index 7c231c622f92..0bc9f33f5cdc 100644 --- a/test/e2e/tests/incremental-security.spec.js +++ b/test/e2e/tests/incremental-security.spec.js @@ -112,10 +112,10 @@ describe('Incremental Security', function () { // should have the correct amount of eth let currencyDisplay = await driver.waitForSelector({ css: '.currency-display-component__text', - text: '$1,700.00', + text: '1', }); let balance = await currencyDisplay.getText(); - assert.strictEqual(balance, '$1,700.00'); + assert.strictEqual(balance, '1'); // backs up the Secret Recovery Phrase // should show a backup reminder @@ -163,11 +163,11 @@ describe('Incremental Security', function () { // should have the correct amount of eth currencyDisplay = await driver.waitForSelector({ css: '.currency-display-component__text', - text: '$1,700.00', + text: '1', }); balance = await currencyDisplay.getText(); - assert.strictEqual(balance, '$1,700.00'); + assert.strictEqual(balance, '1'); // should not show a backup reminder await driver.assertElementNotPresent('.backup-notification'); diff --git a/test/e2e/tests/localization.spec.js b/test/e2e/tests/localization.spec.js index 6c0e0295f097..7c8c35d3d169 100644 --- a/test/e2e/tests/localization.spec.js +++ b/test/e2e/tests/localization.spec.js @@ -27,7 +27,7 @@ describe('Localization', function () { await unlockWallet(driver); const secondaryBalance = await driver.findElement( - '[data-testid="eth-overview__primary-currency"]', + '[data-testid="eth-overview__secondary-currency"]', ); const secondaryBalanceText = await secondaryBalance.getText(); const [fiatAmount, fiatUnit] = secondaryBalanceText diff --git a/test/e2e/tests/lock-account.spec.js b/test/e2e/tests/lock-account.spec.js index 9ef084b17a7c..a4d23ab7838f 100644 --- a/test/e2e/tests/lock-account.spec.js +++ b/test/e2e/tests/lock-account.spec.js @@ -30,7 +30,7 @@ describe('Lock and unlock', function () { const walletBalance = await driver.findElement( '.eth-overview__primary-balance', ); - assert.equal(await walletBalance.getText(), '$42,500.00\nUSD'); + assert.equal(/^25\s*ETH$/u.test(await walletBalance.getText()), true); }, ); }); diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/metamask-responsive-ui.spec.js index c9aa4667bc1d..033b1611ca7b 100644 --- a/test/e2e/tests/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/metamask-responsive-ui.spec.js @@ -74,9 +74,9 @@ describe('MetaMask Responsive UI', function () { await driver.waitForElementNotPresent('.loading-overlay__spinner'); // assert balance const balance = await driver.findElement( - '.eth-overview__primary-container', + '[data-testid="eth-overview__primary-currency"]', ); - assert.equal(await balance.getText(), '$0.00\nUSD'); + assert.ok(/^0\sETH$/u.test(await balance.getText())); }, ); }); diff --git a/test/e2e/tests/migrate-old-vault.spec.js b/test/e2e/tests/migrate-old-vault.spec.js index 82b6c846b2d9..93bd07010bbe 100644 --- a/test/e2e/tests/migrate-old-vault.spec.js +++ b/test/e2e/tests/migrate-old-vault.spec.js @@ -32,7 +32,7 @@ describe('Migrate vault with old encryption', function () { const walletBalance = await driver.findElement( '.eth-overview__primary-balance', ); - assert.equal(await walletBalance.getText(), '$42,500.00\nUSD'); + assert.equal(/^25\s*ETH$/u.test(await walletBalance.getText()), true); }, ); }); diff --git a/test/e2e/tests/send-eth.spec.js b/test/e2e/tests/send-eth.spec.js index 8d8d86bd873d..32b649bfd0d2 100644 --- a/test/e2e/tests/send-eth.spec.js +++ b/test/e2e/tests/send-eth.spec.js @@ -190,7 +190,7 @@ describe('Send ETH', function () { const balance = await driver.findElement( '[data-testid="eth-overview__primary-currency"]', ); - assert.equal(await balance.getText(), '$42,496.38\nUSD'); + assert.ok(/^[\d.]+\sETH$/u.test(await balance.getText())); await driver.clickElement('[data-testid="home__activity-tab"]'); await driver.findElement( @@ -215,12 +215,13 @@ describe('Send ETH', function () { return; } await unlockWallet(driver); + + await driver.assertElementNotPresent('.loading-overlay__spinner'); const balance = await driver.findElement( '[data-testid="eth-overview__primary-currency"]', ); - await driver.isElementPresent('.loading-overlay__spinner'); - await driver.waitForElementNotPresent('.loading-overlay__spinner'); - assert.equal(await balance.getText(), '$42,500.00\nUSD'); + assert.ok(/^[\d.]+\sETH$/u.test(await balance.getText())); + await openActionMenuAndStartSendFlow(driver); // choose to scan via QR code await driver.clickElement('[data-testid="ens-qr-scan-button"]'); @@ -419,13 +420,12 @@ describe('Send ETH', function () { }, async ({ driver }) => { await unlockWallet(driver); + + await driver.assertElementNotPresent('.loading-overlay__spinner'); const balance = await driver.findElement( '[data-testid="eth-overview__primary-currency"]', ); - - await driver.isElementPresent('.loading-overlay__spinner'); - await driver.waitForElementNotPresent('.loading-overlay__spinner'); - assert.equal(await balance.getText(), '$42,500.00\nUSD'); + assert.ok(/^[\d.]+\sETH$/u.test(await balance.getText())); await openActionMenuAndStartSendFlow(driver); if (process.env.MULTICHAIN) { diff --git a/ui/components/app/wallet-overview/eth-overview.js b/ui/components/app/wallet-overview/eth-overview.js index dece08d61f14..ebe77325a386 100644 --- a/ui/components/app/wallet-overview/eth-overview.js +++ b/ui/components/app/wallet-overview/eth-overview.js @@ -27,14 +27,11 @@ import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import { isBalanceCached, + getShouldShowFiat, getIsSwapsChain, getCurrentChainId, getPreferences, - getSelectedAddress, - getShouldHideZeroBalanceTokens, - getCurrentNetwork, getSelectedAccountCachedBalance, - getShowFiatInTestnets, ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask) getSwapsDefaultToken, getCurrentKeyring, @@ -65,11 +62,9 @@ import { IconColor } from '../../../helpers/constants/design-system'; import useRamps from '../../../hooks/experiences/useRamps'; import { getPortfolioUrl } from '../../../helpers/utils/portfolio'; ///: END:ONLY_INCLUDE_IF -import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance'; import { useIsOriginalNativeTokenSymbol } from '../../../hooks/useIsOriginalNativeTokenSymbol'; import { getProviderConfig } from '../../../ducks/metamask/metamask'; import { showPrimaryCurrency } from '../../../../shared/modules/currency-display.utils'; -import { TEST_NETWORKS } from '../../../../shared/constants/network'; import WalletOverview from './wallet-overview'; const EthOverview = ({ className, showAddress }) => { @@ -87,10 +82,10 @@ const EthOverview = ({ className, showAddress }) => { const defaultSwapsToken = useSelector(getSwapsDefaultToken); ///: END:ONLY_INCLUDE_IF const balanceIsCached = useSelector(isBalanceCached); + const showFiat = useSelector(getShouldShowFiat); const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); const chainId = useSelector(getCurrentChainId); const { ticker, type } = useSelector(getProviderConfig); - const currentNetwork = useSelector(getCurrentNetwork); const balance = useSelector(getSelectedAccountCachedBalance); const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol( chainId, @@ -98,25 +93,6 @@ const EthOverview = ({ className, showAddress }) => { type, ); - // Total fiat balance - const selectedAddress = useSelector(getSelectedAddress); - const shouldHideZeroBalanceTokens = useSelector( - getShouldHideZeroBalanceTokens, - ); - const { totalWeiBalance } = useAccountTotalFiatBalance( - selectedAddress, - shouldHideZeroBalanceTokens, - ); - const showFiatInTestnets = useSelector(getShowFiatInTestnets); - const showFiat = - TEST_NETWORKS.includes(currentNetwork?.nickname) && !showFiatInTestnets; - - let balanceToUse = totalWeiBalance; - - if (showFiat) { - balanceToUse = balance; - } - const isSwapsChain = useSelector(getIsSwapsChain); ///: BEGIN:ONLY_INCLUDE_IF(build-mmi) @@ -186,14 +162,14 @@ const EthOverview = ({ className, showAddress }) => { >
- {balanceToUse ? ( + {balance ? ( { ? PRIMARY : SECONDARY } - showFiat={ - !showFiat || - !TEST_NETWORKS.includes(currentNetwork?.nickname) - } ethNumberOfDecimals={4} hideTitle /> @@ -219,6 +191,19 @@ const EthOverview = ({ className, showAddress }) => { * ) : null}
+ {showFiat && isOriginalNativeSymbol && balance && ( + + )}
} diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js index 2b0bc7935eb0..959a38678677 100644 --- a/ui/components/app/wallet-overview/eth-overview.test.js +++ b/ui/components/app/wallet-overview/eth-overview.test.js @@ -171,7 +171,7 @@ describe('EthOverview', () => { const primaryBalance = queryByTestId(ETH_OVERVIEW_PRIMARY_CURRENCY); expect(primaryBalance).toBeInTheDocument(); - expect(primaryBalance).toHaveTextContent('$0.00USD'); + expect(primaryBalance).toHaveTextContent('<0.000001ETH'); expect(queryByText('*')).not.toBeInTheDocument(); }); @@ -202,7 +202,7 @@ describe('EthOverview', () => { const primaryBalance = queryByTestId(ETH_OVERVIEW_PRIMARY_CURRENCY); expect(primaryBalance).toBeInTheDocument(); - expect(primaryBalance).toHaveTextContent('$0.02USD'); + expect(primaryBalance).toHaveTextContent('0.0104ETH'); expect(queryByText('*')).toBeInTheDocument(); }); From 6b1e892d7b565581c80115de2d863c49e4d3cfd0 Mon Sep 17 00:00:00 2001 From: Brian Bergeron Date: Wed, 20 Mar 2024 14:41:15 -0700 Subject: [PATCH 54/55] fix: test for v11.12.4 release (#23619) Fix test for v11.12.4 release --- test/e2e/tests/send-eth.spec.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/e2e/tests/send-eth.spec.js b/test/e2e/tests/send-eth.spec.js index 32b649bfd0d2..aeb9a1995720 100644 --- a/test/e2e/tests/send-eth.spec.js +++ b/test/e2e/tests/send-eth.spec.js @@ -216,10 +216,11 @@ describe('Send ETH', function () { } await unlockWallet(driver); - await driver.assertElementNotPresent('.loading-overlay__spinner'); const balance = await driver.findElement( '[data-testid="eth-overview__primary-currency"]', ); + await driver.isElementPresent('.loading-overlay__spinner'); + await driver.waitForElementNotPresent('.loading-overlay__spinner'); assert.ok(/^[\d.]+\sETH$/u.test(await balance.getText())); await openActionMenuAndStartSendFlow(driver); @@ -421,10 +422,11 @@ describe('Send ETH', function () { async ({ driver }) => { await unlockWallet(driver); - await driver.assertElementNotPresent('.loading-overlay__spinner'); const balance = await driver.findElement( '[data-testid="eth-overview__primary-currency"]', ); + await driver.isElementPresent('.loading-overlay__spinner'); + await driver.waitForElementNotPresent('.loading-overlay__spinner'); assert.ok(/^[\d.]+\sETH$/u.test(await balance.getText())); await openActionMenuAndStartSendFlow(driver); From cda3bdd5348847c870daae5d4599de22265817c2 Mon Sep 17 00:00:00 2001 From: Bowen Sanders Date: Wed, 20 Mar 2024 14:51:02 -0700 Subject: [PATCH 55/55] fix: fix typo in snap install rejected metric (#23618) ## **Description** Fixes a typo in the name for the `SnapInstallRejected` MetaMetrics event. [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/23618?quickstart=1) --- shared/constants/metametrics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 397fa0472039..4a02b88d461c 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -662,7 +662,7 @@ export enum MetaMetricsEventName { ///: BEGIN:ONLY_INCLUDE_IF(snaps) SnapInstallStarted = 'Snap Install Started', SnapInstallFailed = 'Snap Install Failed', - SnapInstallRejected = 'Snap Update Rejected', + SnapInstallRejected = 'Snap Install Rejected', SnapInstalled = 'Snap Installed', SnapUninstalled = 'Snap Uninstalled', SnapUpdateStarted = 'Snap Update Started',