From 402db4e94ee05acfb08075e3f52cb107f587fdad Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Thu, 28 Apr 2022 22:32:12 +0000 Subject: [PATCH 01/27] Version v10.15.0 --- CHANGELOG.md | 48 +++++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d271b47a3..47decfa34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.15.0] +### Uncategorized +- Unit test proptype ([#14509](https://github.com/MetaMask/metamask-extension/pull/14509)) +- Sync `master` with `develop` ([#14562](https://github.com/MetaMask/metamask-extension/pull/14562)) +- Revert "Revert "Dark Mode: What's New Announcement ([#14346](https://github.com/MetaMask/metamask-extension/pull/14346)) +- Merge remote-tracking branch 'origin/develop' into master-sync +- Lavamoat - protect all UI contexts ([#14537](https://github.com/MetaMask/metamask-extension/pull/14537)) +- snaps-skunkworks@0.11.1 ([#14531](https://github.com/MetaMask/metamask-extension/pull/14531)) +- Updating text/muted to text/alternative for select text on home screen ([#14553](https://github.com/MetaMask/metamask-extension/pull/14553)) +- Dark Mode : Add OS option in theme selection dropdown ([#14379](https://github.com/MetaMask/metamask-extension/pull/14379)) +- Update Dark Mode What's New message ([#14535](https://github.com/MetaMask/metamask-extension/pull/14535)) +- Adding 'Swaps' to metametrics event categories ([#14538](https://github.com/MetaMask/metamask-extension/pull/14538)) +- Create new e2e test for bip-44 snap in test-snaps ([#14440](https://github.com/MetaMask/metamask-extension/pull/14440)) +- Warn about multiple MetaMask instances running ([#13836](https://github.com/MetaMask/metamask-extension/pull/13836)) +- Fixed API for watchAsset ([#14545](https://github.com/MetaMask/metamask-extension/pull/14545)) +- Rename NotificationController to AnnouncementController ([#14389](https://github.com/MetaMask/metamask-extension/pull/14389)) +- Adjust package version to 10.13.0 ([#14540](https://github.com/MetaMask/metamask-extension/pull/14540)) +- Add token standard to custom token details ([#14506](https://github.com/MetaMask/metamask-extension/pull/14506)) +- lavamoat@6 - update to secure package naming ([#14488](https://github.com/MetaMask/metamask-extension/pull/14488)) +- Fixing 'Learn more' casing on import token screen ([#14529](https://github.com/MetaMask/metamask-extension/pull/14529)) +- call controller methods directly in send duck ([#14465](https://github.com/MetaMask/metamask-extension/pull/14465)) +- show token approval details on confirm approve screen by default ([#14523](https://github.com/MetaMask/metamask-extension/pull/14523)) +- i18n - remove unused locale strings ([#14527](https://github.com/MetaMask/metamask-extension/pull/14527)) +- Do not show failed off-chain transactions details when grouped with another valid transaction of same nonce ([#14497](https://github.com/MetaMask/metamask-extension/pull/14497)) +- Update for a new Add network page ([#13866](https://github.com/MetaMask/metamask-extension/pull/13866)) +- Update display of switching current network ([#13450](https://github.com/MetaMask/metamask-extension/pull/13450)) +- Ensure network name in confirm page container is defined ([#14520](https://github.com/MetaMask/metamask-extension/pull/14520)) +- New Crowdin translations by Github Action ([#13556](https://github.com/MetaMask/metamask-extension/pull/13556)) +- MetaMetrics: Add EVENT.CATEGORIES const ([#14474](https://github.com/MetaMask/metamask-extension/pull/14474)) +- Update tx data for simpleSends and add isBestQuote to swaps data ([#14496](https://github.com/MetaMask/metamask-extension/pull/14496)) +- Feature/remove bitmask ([#14489](https://github.com/MetaMask/metamask-extension/pull/14489)) +- MetaMetrics: add 'number_of_nfts' user trait ([#14495](https://github.com/MetaMask/metamask-extension/pull/14495)) +- Add testnet name as prefix for native currency of preloaded testnets ([#14454](https://github.com/MetaMask/metamask-extension/pull/14454)) +- Fix ESLint config around files w/ CommonJS imports ([#14380](https://github.com/MetaMask/metamask-extension/pull/14380)) +- Add new token added event (duplicating the existing event structure) when collectible is manually added ([#14279](https://github.com/MetaMask/metamask-extension/pull/14279)) +- increase test coverage of nonce sorted transaction selector ([#14486](https://github.com/MetaMask/metamask-extension/pull/14486)) +- Fix the alerts toggles in settings ([#14498](https://github.com/MetaMask/metamask-extension/pull/14498)) +- Disable swaps whenever the environment is not development or testing, so that behaviour follows production for QA purposes ([#14499](https://github.com/MetaMask/metamask-extension/pull/14499)) +- E2e test timeout ([#14483](https://github.com/MetaMask/metamask-extension/pull/14483)) +- Stop storing request and response objects in the permission activity log ([#14485](https://github.com/MetaMask/metamask-extension/pull/14485)) +- increase test coverage of nonce sorted transaction selector ([#14479](https://github.com/MetaMask/metamask-extension/pull/14479)) +- bump crowdin/github-action ([#14475](https://github.com/MetaMask/metamask-extension/pull/14475)) +- E2e readme docs ([#14434](https://github.com/MetaMask/metamask-extension/pull/14434)) +- E2e connected state ([#14444](https://github.com/MetaMask/metamask-extension/pull/14444)) + ## [10.14.0] ### Added - **[FLASK]** Add snap version to details page ([#14110](https://github.com/MetaMask/metamask-extension/pull/14110)) @@ -2908,7 +2953,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.14.0...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.15.0...HEAD +[10.15.0]: https://github.com/MetaMask/metamask-extension/compare/v10.14.0...v10.15.0 [10.14.0]: https://github.com/MetaMask/metamask-extension/compare/v10.13.0...v10.14.0 [10.13.0]: https://github.com/MetaMask/metamask-extension/compare/v10.12.4...v10.13.0 [10.12.4]: https://github.com/MetaMask/metamask-extension/compare/v10.12.3...v10.12.4 diff --git a/package.json b/package.json index 0c6be9912..36f9abbb8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.14.0", + "version": "10.15.0", "private": true, "repository": { "type": "git", From 2a3b77c95fe048760af0835b6688048bdc11191b Mon Sep 17 00:00:00 2001 From: ryanml Date: Mon, 2 May 2022 23:07:23 -0700 Subject: [PATCH 02/27] [skip e2e] Update changelog for v10.15.0 (#14593) --- CHANGELOG.md | 55 +++++++++++++--------------------------------------- 1 file changed, 13 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47decfa34..69b03943e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,49 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ## [10.15.0] -### Uncategorized -- Unit test proptype ([#14509](https://github.com/MetaMask/metamask-extension/pull/14509)) -- Sync `master` with `develop` ([#14562](https://github.com/MetaMask/metamask-extension/pull/14562)) -- Revert "Revert "Dark Mode: What's New Announcement ([#14346](https://github.com/MetaMask/metamask-extension/pull/14346)) -- Merge remote-tracking branch 'origin/develop' into master-sync -- Lavamoat - protect all UI contexts ([#14537](https://github.com/MetaMask/metamask-extension/pull/14537)) -- snaps-skunkworks@0.11.1 ([#14531](https://github.com/MetaMask/metamask-extension/pull/14531)) -- Updating text/muted to text/alternative for select text on home screen ([#14553](https://github.com/MetaMask/metamask-extension/pull/14553)) -- Dark Mode : Add OS option in theme selection dropdown ([#14379](https://github.com/MetaMask/metamask-extension/pull/14379)) -- Update Dark Mode What's New message ([#14535](https://github.com/MetaMask/metamask-extension/pull/14535)) -- Adding 'Swaps' to metametrics event categories ([#14538](https://github.com/MetaMask/metamask-extension/pull/14538)) -- Create new e2e test for bip-44 snap in test-snaps ([#14440](https://github.com/MetaMask/metamask-extension/pull/14440)) -- Warn about multiple MetaMask instances running ([#13836](https://github.com/MetaMask/metamask-extension/pull/13836)) -- Fixed API for watchAsset ([#14545](https://github.com/MetaMask/metamask-extension/pull/14545)) -- Rename NotificationController to AnnouncementController ([#14389](https://github.com/MetaMask/metamask-extension/pull/14389)) -- Adjust package version to 10.13.0 ([#14540](https://github.com/MetaMask/metamask-extension/pull/14540)) -- Add token standard to custom token details ([#14506](https://github.com/MetaMask/metamask-extension/pull/14506)) -- lavamoat@6 - update to secure package naming ([#14488](https://github.com/MetaMask/metamask-extension/pull/14488)) -- Fixing 'Learn more' casing on import token screen ([#14529](https://github.com/MetaMask/metamask-extension/pull/14529)) -- call controller methods directly in send duck ([#14465](https://github.com/MetaMask/metamask-extension/pull/14465)) -- show token approval details on confirm approve screen by default ([#14523](https://github.com/MetaMask/metamask-extension/pull/14523)) -- i18n - remove unused locale strings ([#14527](https://github.com/MetaMask/metamask-extension/pull/14527)) +### Added +- **[FLASK]** - Add warning when multiple instances of MetaMask are running ([#13836](https://github.com/MetaMask/metamask-extension/pull/13836)) +- Theme: Add OS option in theme selection dropdown ([#14379](https://github.com/MetaMask/metamask-extension/pull/14379)) + +### Changed +- Use testname as the base currency prefix for preloaded test networks ([#14454](https://github.com/MetaMask/metamask-extension/pull/14454)) +- Update UI of "Add Network" page ([#13866](https://github.com/MetaMask/metamask-extension/pull/13866)) +- Update UI of network switch permissions prompt ([#13450](https://github.com/MetaMask/metamask-extension/pull/13450)) +- Show token approval details on approval screens by default ([#14523](https://github.com/MetaMask/metamask-extension/pull/14523)) +- Update "What's New" announcement text for Dark Mode ([#14535](https://github.com/MetaMask/metamask-extension/pull/14535)) + +### Fixed +- Fix `wallet_watchAsset method` ([#14545](https://github.com/MetaMask/metamask-extension/pull/14545)) - Do not show failed off-chain transactions details when grouped with another valid transaction of same nonce ([#14497](https://github.com/MetaMask/metamask-extension/pull/14497)) -- Update for a new Add network page ([#13866](https://github.com/MetaMask/metamask-extension/pull/13866)) -- Update display of switching current network ([#13450](https://github.com/MetaMask/metamask-extension/pull/13450)) -- Ensure network name in confirm page container is defined ([#14520](https://github.com/MetaMask/metamask-extension/pull/14520)) -- New Crowdin translations by Github Action ([#13556](https://github.com/MetaMask/metamask-extension/pull/13556)) -- MetaMetrics: Add EVENT.CATEGORIES const ([#14474](https://github.com/MetaMask/metamask-extension/pull/14474)) -- Update tx data for simpleSends and add isBestQuote to swaps data ([#14496](https://github.com/MetaMask/metamask-extension/pull/14496)) -- Feature/remove bitmask ([#14489](https://github.com/MetaMask/metamask-extension/pull/14489)) -- MetaMetrics: add 'number_of_nfts' user trait ([#14495](https://github.com/MetaMask/metamask-extension/pull/14495)) -- Add testnet name as prefix for native currency of preloaded testnets ([#14454](https://github.com/MetaMask/metamask-extension/pull/14454)) -- Fix ESLint config around files w/ CommonJS imports ([#14380](https://github.com/MetaMask/metamask-extension/pull/14380)) -- Add new token added event (duplicating the existing event structure) when collectible is manually added ([#14279](https://github.com/MetaMask/metamask-extension/pull/14279)) -- increase test coverage of nonce sorted transaction selector ([#14486](https://github.com/MetaMask/metamask-extension/pull/14486)) -- Fix the alerts toggles in settings ([#14498](https://github.com/MetaMask/metamask-extension/pull/14498)) -- Disable swaps whenever the environment is not development or testing, so that behaviour follows production for QA purposes ([#14499](https://github.com/MetaMask/metamask-extension/pull/14499)) -- E2e test timeout ([#14483](https://github.com/MetaMask/metamask-extension/pull/14483)) -- Stop storing request and response objects in the permission activity log ([#14485](https://github.com/MetaMask/metamask-extension/pull/14485)) -- increase test coverage of nonce sorted transaction selector ([#14479](https://github.com/MetaMask/metamask-extension/pull/14479)) -- bump crowdin/github-action ([#14475](https://github.com/MetaMask/metamask-extension/pull/14475)) -- E2e readme docs ([#14434](https://github.com/MetaMask/metamask-extension/pull/14434)) -- E2e connected state ([#14444](https://github.com/MetaMask/metamask-extension/pull/14444)) ## [10.14.0] ### Added From 8a141fe28c85c3eeb14d03a855e86dcd39ff8e7e Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Fri, 29 Apr 2022 12:41:35 -0500 Subject: [PATCH 03/27] fix cross-fetch moderate vulnerability alert (#14570) --- package.json | 1 + yarn.lock | 28 +--------------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 36f9abbb8..53ae1a4c8 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "resolutions": { "**/regenerator-runtime": "^0.13.7", "**/caniuse-lite": "1.0.30001265", + "**/cross-fetch": "^3.1.5", "**/configstore/dot-prop": "^5.1.1", "**/ethers/elliptic": "^6.5.4", "**/knex/minimist": "^1.2.5", diff --git a/yarn.lock b/yarn.lock index b80a6a246..a232ee637 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8913,23 +8913,7 @@ create-react-context@0.3.0: gud "^1.0.0" warning "^4.0.3" -cross-fetch@2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.2.tgz#a47ff4f7fc712daba8f6a695a11c948440d45723" - integrity sha1-pH/09/xxLauo9qaVoRyUhEDUVyM= - dependencies: - node-fetch "2.1.2" - whatwg-fetch "2.0.4" - -cross-fetch@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.3.tgz#e8a0b3c54598136e037f8650f8e823ccdfac198e" - integrity sha512-PrWWNH3yL2NYIb/7WF/5vFG3DCQiXDOVf8k3ijatbrtnwNuhMWLC7YF7uqf53tbTFDzHIUD8oITw4Bxt8ST3Nw== - dependencies: - node-fetch "2.1.2" - whatwg-fetch "2.0.4" - -cross-fetch@^3.1.4: +cross-fetch@2.2.2, cross-fetch@^2.1.0, cross-fetch@^3.1.4, cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -19820,11 +19804,6 @@ node-environment-flags@1.0.6: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" -node-fetch@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" - integrity sha1-q4hOjn5X44qUR1POxwb3iNF2i7U= - node-fetch@2.6.7, node-fetch@^2.3.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@~2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -27945,11 +27924,6 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - whatwg-fetch@^3.4.1: version "3.6.2" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" From a96d40957b45c7dd2f36ddde547a4940e07291a6 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 2 May 2022 23:49:01 +0200 Subject: [PATCH 04/27] Stop using 4bytes for contract deployment (#14598) --- test/data/transaction-data.json | 58 ++++++++++++++++++++++ ui/hooks/useTransactionDisplayData.js | 11 ++-- ui/hooks/useTransactionDisplayData.test.js | 13 +++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/test/data/transaction-data.json b/test/data/transaction-data.json index dbc1ec138..a5219dbdb 100644 --- a/test/data/transaction-data.json +++ b/test/data/transaction-data.json @@ -798,5 +798,63 @@ }, "hasRetried": false, "hasCancelled": false + }, + { + "initialTransaction": { + "blockNumber": "6195527", + "id": 4243712234858468, + "metamaskNetworkId": "4", + "status": "confirmed", + "time": 1585088013000, + "txParams": { + "from": "0xee014609ef9e09776ac5fe00bdbfef57bcdefebb", + "gas": "0x5208", + "gasPrice": "0x77359400", + "nonce": "0x3", + "value": "0x00", + "data": "0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029" + }, + "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", + "type": "contractDeployment", + "origin": "https://metamask.github.io" + }, + "transactions": [ + { + "blockNumber": "6195527", + "id": 4243712234858468, + "metamaskNetworkId": "4", + "status": "confirmed", + "time": 1585088013000, + "txParams": { + "from": "0xee014609ef9e09776ac5fe00bdbfef57bcdefebb", + "gas": "0x5208", + "gasPrice": "0x77359400", + "nonce": "0x3", + "value": "0x00", + "data": "0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029" + }, + "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", + "type": "contractDeployment" + } + ], + "primaryTransaction": { + "blockNumber": "6195527", + "id": 4243712234858468, + "metamaskNetworkId": "4", + "status": "confirmed", + "time": 1585088013000, + "txParams": { + "from": "0xee014609ef9e09776ac5fe00bdbfef57bcdefebb", + "gas": "0x5208", + "gasPrice": "0x77359400", + "nonce": "0x3", + "value": "0x00", + "data": "0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029" + }, + "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", + "type": "contractDeployment" + }, + "hasRetried": false, + "hasCancelled": false } ] diff --git a/ui/hooks/useTransactionDisplayData.js b/ui/hooks/useTransactionDisplayData.js index a56181e03..02a64bdbf 100644 --- a/ui/hooks/useTransactionDisplayData.js +++ b/ui/hooks/useTransactionDisplayData.js @@ -217,10 +217,7 @@ export function useTransactionDisplayData(transactionGroup) { title = t('approveSpendLimit', [token?.symbol || t('token')]); subtitle = origin; subtitleContainsOrigin = true; - } else if ( - type === TRANSACTION_TYPES.DEPLOY_CONTRACT || - type === TRANSACTION_TYPES.CONTRACT_INTERACTION - ) { + } else if (type === TRANSACTION_TYPES.CONTRACT_INTERACTION) { category = TRANSACTION_GROUP_CATEGORIES.INTERACTION; const transactionTypeTitle = getTransactionTypeTitle(t, type); title = @@ -228,6 +225,12 @@ export function useTransactionDisplayData(transactionGroup) { transactionTypeTitle; subtitle = origin; subtitleContainsOrigin = true; + } else if (type === TRANSACTION_TYPES.DEPLOY_CONTRACT) { + // @todo Should perhaps be a separate group? + category = TRANSACTION_GROUP_CATEGORIES.INTERACTION; + title = getTransactionTypeTitle(t, type); + subtitle = origin; + subtitleContainsOrigin = true; } else if (type === TRANSACTION_TYPES.INCOMING) { category = TRANSACTION_GROUP_CATEGORIES.RECEIVE; title = t('receive'); diff --git a/ui/hooks/useTransactionDisplayData.test.js b/ui/hooks/useTransactionDisplayData.test.js index 4c35bee3b..c9673daff 100644 --- a/ui/hooks/useTransactionDisplayData.test.js +++ b/ui/hooks/useTransactionDisplayData.test.js @@ -117,6 +117,19 @@ const expectedResults = [ isPending: false, displayedStatusKey: TRANSACTION_STATUSES.CONFIRMED, }, + { + title: 'Contract Deployment', + category: TRANSACTION_GROUP_CATEGORIES.INTERACTION, + subtitle: 'metamask.github.io', + subtitleContainsOrigin: true, + date: 'May 12, 2020', + primaryCurrency: '-0 ETH', + senderAddress: '0xee014609ef9e09776ac5fe00bdbfef57bcdefebb', + recipientAddress: undefined, + secondaryCurrency: '-0 ETH', + isPending: false, + displayedStatusKey: TRANSACTION_STATUSES.CONFIRMED, + }, ]; let useSelector, useI18nContext, useTokenFiatAmount; From c0957866a9a5213d98881adb9c6432a27535001d Mon Sep 17 00:00:00 2001 From: Ariella Vu <20778143+digiwand@users.noreply.github.com> Date: Tue, 3 May 2022 18:17:08 -0500 Subject: [PATCH 05/27] metametrics: deprecate flatMap (#14608) --- app/scripts/controllers/metametrics.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 9018b533d..856461a57 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -621,7 +621,9 @@ export default class MetaMetricsController { */ _getAllNFTsFlattened = memoize((allCollectibles = {}) => { return Object.values(allCollectibles) - .flatMap((chainNFTs) => Object.values(chainNFTs)) + .reduce((result, chainNFTs) => { + return result.concat(Object.values(chainNFTs)); + }, []) .flat(); }); From f4094925f0f8e8a12e5b2f272a8402f0d5318af5 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 12 May 2022 13:36:14 -0230 Subject: [PATCH 06/27] Ensure ledger keyring message event listener are removed on metamask lock (#14691) * Ensure ledger keyring message event listener are removed on metamask lock * Clean up --- app/scripts/metamask-controller.js | 6 ++++++ lavamoat/browserify/beta/policy.json | 3 ++- lavamoat/browserify/flask/policy.json | 3 ++- lavamoat/browserify/main/policy.json | 3 ++- package.json | 2 +- yarn.lock | 8 ++++---- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6baeb0601..d7a7482c7 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -4104,6 +4104,12 @@ export default class MetamaskController extends EventEmitter { if (trezorKeyring) { trezorKeyring.dispose(); } + + const [ledgerKeyring] = this.keyringController.getKeyringsByType( + KEYRING_TYPES.LEDGER, + ); + ledgerKeyring?.destroy?.(); + return this.keyringController.setLocked(); } diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 2d82ff97e..f9e3d233a 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -2750,7 +2750,8 @@ "globals": { "clearInterval": true, "setInterval": true, - "setTimeout": true + "setTimeout": true, + "removeEventListener": true }, "packages": { "events": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 6783285f9..078a31177 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -2768,7 +2768,8 @@ "globals": { "clearInterval": true, "setInterval": true, - "setTimeout": true + "setTimeout": true, + "removeEventListener": true }, "packages": { "events": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 2d82ff97e..f9e3d233a 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -2750,7 +2750,8 @@ "globals": { "clearInterval": true, "setInterval": true, - "setTimeout": true + "setTimeout": true, + "removeEventListener": true }, "packages": { "events": true diff --git a/package.json b/package.json index 53ae1a4c8..64ef423f1 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "@metamask/contract-metadata": "^1.31.0", "@metamask/controllers": "^28.0.0", "@metamask/design-tokens": "^1.5.1", - "@metamask/eth-ledger-bridge-keyring": "^0.11.0", + "@metamask/eth-ledger-bridge-keyring": "^0.12.0", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/etherscan-link": "^2.1.0", "@metamask/iframe-execution-environment-service": "^0.11.1", diff --git a/yarn.lock b/yarn.lock index a232ee637..0e6908768 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2842,10 +2842,10 @@ resolved "https://registry.yarnpkg.com/@metamask/eslint-config/-/eslint-config-9.0.0.tgz#22d4911b705f7e4e566efbdda0e37912da33e30f" integrity sha512-mWlLGQKjXXFOj9EtDClKSoTLeQuPW2kM1w3EpUMf4goYAQ+kLXCCa8pEff6h8ApWAnjhYmXydA1znQ2J4XvD+A== -"@metamask/eth-ledger-bridge-keyring@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@metamask/eth-ledger-bridge-keyring/-/eth-ledger-bridge-keyring-0.11.0.tgz#8502e2fd36c89aff7de6724354217274917cecd3" - integrity sha512-fCwM8LYC6SXLfsKc4oNiAatz2X8p/pjbM5zMfm4nb4sZPshBAWU32M4vnB3BSVeQEsisGuLfOWCOWhxmq25n+Q== +"@metamask/eth-ledger-bridge-keyring@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@metamask/eth-ledger-bridge-keyring/-/eth-ledger-bridge-keyring-0.12.0.tgz#d3986e0dbbfeab713f4e0338bf4e5c74a2265bdd" + integrity sha512-kceBQc/wKCAdChZeI1P0Fs0FS15WtiD2Q87MqmfuJYpOriWRx/RmjKZoa6EJe2vy20KurlZRcKIiU8nFQ0e/ag== dependencies: "@ethereumjs/tx" "^3.2.0" eth-sig-util "^2.0.0" From 214211f847941221e8d328352d8b4260e56ab86c Mon Sep 17 00:00:00 2001 From: ryanml Date: Mon, 16 May 2022 07:07:19 -0700 Subject: [PATCH 07/27] Update Lavamoat policies --- lavamoat/browserify/beta/policy.json | 3 ++- lavamoat/browserify/flask/policy.json | 3 ++- lavamoat/browserify/main/policy.json | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index f9e3d233a..126796a99 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -585,7 +585,8 @@ "console.log": true, "document.createElement": true, "document.head.appendChild": true, - "fetch": true + "fetch": true, + "removeEventListener": true }, "packages": { "@ethereumjs/tx": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 078a31177..8f7562e63 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -585,7 +585,8 @@ "console.log": true, "document.createElement": true, "document.head.appendChild": true, - "fetch": true + "fetch": true, + "removeEventListener": true }, "packages": { "@ethereumjs/tx": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index f9e3d233a..126796a99 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -585,7 +585,8 @@ "console.log": true, "document.createElement": true, "document.head.appendChild": true, - "fetch": true + "fetch": true, + "removeEventListener": true }, "packages": { "@ethereumjs/tx": true, From f251ca4ff236864983f6ebe933c28ee77711fee0 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Wed, 4 May 2022 11:54:46 -0500 Subject: [PATCH 08/27] Track send flow history on txMeta (#14510) --- app/scripts/controllers/transactions/index.js | 38 ++- .../transactions/tx-state-manager.js | 1 + app/scripts/metamask-controller.js | 3 + ui/ducks/send/send.js | 100 +++++- ui/ducks/send/send.test.js | 293 +++++++++++++----- .../add-recipient/add-recipient.component.js | 20 +- .../add-recipient/add-recipient.container.js | 2 + ui/pages/send/send.js | 19 +- ui/store/actions.js | 30 ++ 9 files changed, 415 insertions(+), 91 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index e982b962f..e5d50375f 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -647,6 +647,35 @@ export default class TransactionController extends EventEmitter { return this._getTransaction(txId); } + /** + * append new sendFlowHistory to the transaction with id if the transaction + * state is unapproved. Returns the updated transaction. + * + * @param {string} txId - transaction id + * @param {Array<{ entry: string, timestamp: number }>} sendFlowHistory - + * history to add to the sendFlowHistory property of txMeta. + * @returns {TransactionMeta} the txMeta of the updated transaction + */ + updateTransactionSendFlowHistory(txId, sendFlowHistory) { + this._throwErrorIfNotUnapprovedTx(txId, 'updateTransactionSendFlowHistory'); + const txMeta = this._getTransaction(txId); + + // only update what is defined + const note = `Update sendFlowHistory for ${txId}`; + + this.txStateManager.updateTransaction( + { + ...txMeta, + sendFlowHistory: [ + ...(txMeta?.sendFlowHistory ?? []), + ...sendFlowHistory, + ], + }, + note, + ); + return this._getTransaction(txId); + } + // ==================================================================================================================================================== /** @@ -656,9 +685,15 @@ export default class TransactionController extends EventEmitter { * @param txParams * @param origin * @param transactionType + * @param sendFlowHistory * @returns {txMeta} */ - async addUnapprovedTransaction(txParams, origin, transactionType) { + async addUnapprovedTransaction( + txParams, + origin, + transactionType, + sendFlowHistory = [], + ) { if ( transactionType !== undefined && !VALID_UNAPPROVED_TRANSACTION_TYPES.includes(transactionType) @@ -683,6 +718,7 @@ export default class TransactionController extends EventEmitter { let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams, origin, + sendFlowHistory, }); if (origin === ORIGIN_METAMASK) { diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 111392fad..33e23bbf8 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -127,6 +127,7 @@ export default class TransactionStateManager extends EventEmitter { chainId, loadingDefaults: true, dappSuggestedGasFees, + sendFlowHistory: [], ...opts, }; } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d7a7482c7..fea64e68d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1632,6 +1632,9 @@ export default class MetamaskController extends EventEmitter { updateTransactionGasFees: txController.updateTransactionGasFees.bind( txController, ), + updateTransactionSendFlowHistory: txController.updateTransactionSendFlowHistory.bind( + txController, + ), updateSwapApprovalTransaction: txController.updateSwapApprovalTransaction.bind( txController, diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 76546ac04..a812e34a1 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -60,6 +60,7 @@ import { getTokenStandardAndDetails, showModal, addUnapprovedTransactionAndRouteToConfirmationPage, + updateTransactionSendFlowHistory, } from '../../store/actions'; import { setCustomGasLimit } from '../gas/gas.duck'; import { @@ -110,6 +111,7 @@ import { import { readAddressAsContract } from '../../../shared/modules/contract-utils'; import { INVALID_ASSET_TYPE } from '../../helpers/constants/error-keys'; import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; +import { getValueFromWeiHex } from '../../helpers/utils/confirm-tx.util'; // typedefs /** * @typedef {import('@reduxjs/toolkit').PayloadAction} PayloadAction @@ -684,12 +686,19 @@ export const initialState = { // Layer 1 gas fee total on multi-layer fee networks layer1GasTotal: '0x0', }, + history: [], }; const slice = createSlice({ name, initialState, reducers: { + addHistoryEntry: (state, action) => { + state.history.push({ + entry: action.payload, + timestamp: Date.now(), + }); + }, /** * update current amount.value in state and run post update validation of * the amount field and the send state. Recomputes the draftTransaction @@ -1402,9 +1411,10 @@ const { updateGasLimit, validateRecipientUserInput, updateRecipientSearchMode, + addHistoryEntry, } = actions; -export { useDefaultGas, useCustomGas, updateGasLimit }; +export { useDefaultGas, useCustomGas, updateGasLimit, addHistoryEntry }; // Action Creators @@ -1421,6 +1431,9 @@ export { useDefaultGas, useCustomGas, updateGasLimit }; */ export function updateGasPrice(gasPrice) { return (dispatch) => { + dispatch( + addHistoryEntry(`sendFlow - user set legacy gasPrice to ${gasPrice}`), + ); dispatch( actions.updateGasFees({ gasPrice, @@ -1452,8 +1465,36 @@ export function resetSendState() { */ export function updateSendAmount(amount) { return async (dispatch, getState) => { - await dispatch(actions.updateSendAmount(amount)); const state = getState(); + let logAmount = amount; + if (state[name].asset.type === ASSET_TYPES.TOKEN) { + const multiplier = Math.pow( + 10, + Number(state[name].asset.details?.decimals || 0), + ); + const decimalValueString = conversionUtil(addHexPrefix(amount), { + fromNumericBase: 'hex', + toNumericBase: 'dec', + toCurrency: state[name].asset.details?.symbol, + conversionRate: multiplier, + invertConversionRate: true, + }); + + logAmount = `${Number(decimalValueString) ? decimalValueString : ''} ${ + state[name].asset.details?.symbol + }`; + } else { + const ethValue = getValueFromWeiHex({ + value: amount, + toCurrency: ETH, + numberOfDecimals: 8, + }); + logAmount = `${ethValue} ${ETH}`; + } + await dispatch( + addHistoryEntry(`sendFlow - user set amount to ${logAmount}`), + ); + await dispatch(actions.updateSendAmount(amount)); if (state.send.amount.mode === AMOUNT_MODES.MAX) { await dispatch(actions.updateAmountMode(AMOUNT_MODES.INPUT)); } @@ -1482,6 +1523,19 @@ export function updateSendAmount(amount) { */ export function updateSendAsset({ type, details }) { return async (dispatch, getState) => { + dispatch(addHistoryEntry(`sendFlow - user set asset type to ${type}`)); + dispatch( + addHistoryEntry( + `sendFlow - user set asset symbol to ${details?.symbol ?? 'undefined'}`, + ), + ); + dispatch( + addHistoryEntry( + `sendFlow - user set asset address to ${ + details?.address ?? 'undefined' + }`, + ), + ); const state = getState(); let { balance, error } = state.send.asset; const userAddress = state.send.account.address ?? getSelectedAddress(state); @@ -1580,6 +1634,11 @@ export function updateSendAsset({ type, details }) { * it only applicable for use within action creators. */ const debouncedValidateRecipientUserInput = debounce((dispatch, payload) => { + dispatch( + addHistoryEntry( + `sendFlow - user typed ${payload.userInput} into recipient input field`, + ), + ); dispatch(validateRecipientUserInput(payload)); }, 300); @@ -1600,6 +1659,7 @@ export function updateRecipientUserInput(userInput) { const useTokenDetection = getUseTokenDetection(state); const tokenAddressList = Object.keys(getTokenList(state)); debouncedValidateRecipientUserInput(dispatch, { + userInput, chainId, tokens, useTokenDetection, @@ -1610,12 +1670,22 @@ export function updateRecipientUserInput(userInput) { export function useContactListForRecipientSearch() { return (dispatch) => { + dispatch( + addHistoryEntry( + `sendFlow - user selected back to all on recipient screen`, + ), + ); dispatch(updateRecipientSearchMode(RECIPIENT_SEARCH_MODES.CONTACT_LIST)); }; } export function useMyAccountsForRecipientSearch() { return (dispatch) => { + dispatch( + addHistoryEntry( + `sendFlow - user selected transfer to my accounts on recipient screen`, + ), + ); dispatch(updateRecipientSearchMode(RECIPIENT_SEARCH_MODES.MY_ACCOUNTS)); }; } @@ -1638,6 +1708,8 @@ export function useMyAccountsForRecipientSearch() { */ export function updateRecipient({ address, nickname }) { return async (dispatch, getState) => { + // Do not addHistoryEntry here as this is called from a number of places + // each with significance to the user and transaction history. const state = getState(); const nicknameFromAddressBookEntryOrAccountName = getAddressBookEntryOrAccountName(state, address) ?? ''; @@ -1656,6 +1728,7 @@ export function updateRecipient({ address, nickname }) { */ export function resetRecipientInput() { return async (dispatch) => { + await dispatch(addHistoryEntry(`sendFlow - user cleared recipient input`)); await dispatch(updateRecipientUserInput('')); await dispatch(updateRecipient({ address: '', nickname: '' })); await dispatch(resetEnsResolution()); @@ -1675,6 +1748,9 @@ export function resetRecipientInput() { */ export function updateSendHexData(hexData) { return async (dispatch, getState) => { + await dispatch( + addHistoryEntry(`sendFlow - user added custom hexData ${hexData}`), + ); await dispatch(actions.updateUserInputHexData(hexData)); const state = getState(); if (state.send.asset.type === ASSET_TYPES.NATIVE) { @@ -1695,9 +1771,11 @@ export function toggleSendMaxMode() { if (state.send.amount.mode === AMOUNT_MODES.MAX) { await dispatch(actions.updateAmountMode(AMOUNT_MODES.INPUT)); await dispatch(actions.updateSendAmount('0x0')); + await dispatch(addHistoryEntry(`sendFlow - user toggled max mode off`)); } else { await dispatch(actions.updateAmountMode(AMOUNT_MODES.MAX)); await dispatch(actions.updateAmountToMax()); + await dispatch(addHistoryEntry(`sendFlow - user toggled max mode on`)); } await dispatch(computeEstimatedGasLimit()); }; @@ -1746,6 +1824,12 @@ export function signTransaction() { eip1559support ? eip1559OnlyTxParamsToUpdate : txParams, ), }; + await dispatch( + addHistoryEntry( + `sendFlow - user clicked next and transaction should be updated in controller`, + ), + ); + await dispatch(updateTransactionSendFlowHistory(id, state[name].history)); dispatch(updateEditableParams(id, editingTx.txParams)); dispatch(updateTransactionGasFees(id, editingTx.txParams)); } else { @@ -1757,10 +1841,17 @@ export function signTransaction() { ? TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM : TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER; } + await dispatch( + addHistoryEntry( + `sendFlow - user clicked next and transaction should be added to controller`, + ), + ); + dispatch( addUnapprovedTransactionAndRouteToConfirmationPage( txParams, transactionType, + state[name].history, ), ); } @@ -1775,6 +1866,11 @@ export function editTransaction( ) { return async (dispatch, getState) => { const state = getState(); + await dispatch( + addHistoryEntry( + `sendFlow - user clicked edit on transaction with id ${transactionId}`, + ), + ); const unapprovedTransactions = getUnapprovedTxs(state); const transaction = unapprovedTransactions[transactionId]; const { txParams } = transaction; diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 8e16486db..a8466753b 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -80,9 +80,10 @@ jest.mock('./send', () => { setBackgroundConnection({ addPollingTokenToAppState: jest.fn(), - addUnapprovedTransaction: jest.fn((_x, _y, _z, cb) => { - return cb(null, {}); + addUnapprovedTransaction: jest.fn((_w, _x, _y, _z, cb) => { + cb(null); }), + updateTransactionSendFlowHistory: jest.fn((_x, _y, cb) => cb(null)), }); describe('Send Slice', () => { @@ -1247,6 +1248,10 @@ describe('Send Slice', () => { const actionResult = store.getActions(); const expectedActionResult = [ + { + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set legacy gasPrice to 0x0', + }, { type: 'send/updateGasFees', payload: { @@ -1302,22 +1307,28 @@ describe('Send Slice', () => { }; const store = mockStore(sendState); - const newSendAmount = 'aNewSendAmount'; + const newSendAmount = 'DE0B6B3A7640000'; await store.dispatch(updateSendAmount(newSendAmount)); const actionResult = store.getActions(); const expectedFirstActionResult = { + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set amount to 1 ETH', + }; + + const expectedSecondActionResult = { type: 'send/updateSendAmount', - payload: 'aNewSendAmount', + payload: 'DE0B6B3A7640000', }; expect(actionResult[0]).toStrictEqual(expectedFirstActionResult); - expect(actionResult[1].type).toStrictEqual( + expect(actionResult[1]).toStrictEqual(expectedSecondActionResult); + expect(actionResult[2].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[3].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -1358,15 +1369,21 @@ describe('Send Slice', () => { const actionResult = store.getActions(); const expectedFirstActionResult = { + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set amount to 0 ETH', + }; + + const expectedSecondActionResult = { type: 'send/updateSendAmount', payload: undefined, }; expect(actionResult[0]).toStrictEqual(expectedFirstActionResult); - expect(actionResult[1].type).toStrictEqual( + expect(actionResult[1]).toStrictEqual(expectedSecondActionResult); + expect(actionResult[2].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[3].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -1407,12 +1424,13 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(3); - expect(actionResult[0].type).toStrictEqual('send/updateSendAmount'); - expect(actionResult[1].type).toStrictEqual( + expect(actionResult).toHaveLength(4); + expect(actionResult[0].type).toStrictEqual('send/addHistoryEntry'); + expect(actionResult[1].type).toStrictEqual('send/updateSendAmount'); + expect(actionResult[2].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[3].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -1466,19 +1484,31 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(3); + expect(actionResult).toHaveLength(6); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset type to ', + }); + expect(actionResult[1]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset symbol to ', + }); + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset address to ', + }); - expect(actionResult[0].type).toStrictEqual('send/updateAsset'); - expect(actionResult[0].payload).toStrictEqual({ + expect(actionResult[3].type).toStrictEqual('send/updateAsset'); + expect(actionResult[3].payload).toStrictEqual({ ...newSendAsset, balance: '', error: null, }); - expect(actionResult[1].type).toStrictEqual( + expect(actionResult[4].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[5].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -1506,19 +1536,31 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(5); - expect(actionResult[0].type).toStrictEqual('SHOW_LOADING_INDICATION'); - expect(actionResult[1].type).toStrictEqual('HIDE_LOADING_INDICATION'); - expect(actionResult[2].payload).toStrictEqual({ + expect(actionResult).toHaveLength(8); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: `sendFlow - user set asset type to ${ASSET_TYPES.TOKEN}`, + }); + expect(actionResult[1]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset symbol to tokenSymbol', + }); + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset address to tokenAddress', + }); + expect(actionResult[3].type).toStrictEqual('SHOW_LOADING_INDICATION'); + expect(actionResult[4].type).toStrictEqual('HIDE_LOADING_INDICATION'); + expect(actionResult[5].payload).toStrictEqual({ ...newSendAsset, balance: '0x0', error: null, }); - expect(actionResult[3].type).toStrictEqual( + expect(actionResult[6].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[4].type).toStrictEqual( + expect(actionResult[7].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -1543,10 +1585,22 @@ describe('Send Slice', () => { store.dispatch(updateSendAsset(newSendAsset)), ).rejects.toThrow('invalidAssetType'); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(3); - expect(actionResult[0].type).toStrictEqual('SHOW_LOADING_INDICATION'); - expect(actionResult[1].type).toStrictEqual('HIDE_LOADING_INDICATION'); - expect(actionResult[2]).toStrictEqual({ + expect(actionResult).toHaveLength(6); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: `sendFlow - user set asset type to ${ASSET_TYPES.TOKEN}`, + }); + expect(actionResult[1]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset symbol to tokenSymbol', + }); + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset address to tokenAddress', + }); + expect(actionResult[3].type).toStrictEqual('SHOW_LOADING_INDICATION'); + expect(actionResult[4].type).toStrictEqual('HIDE_LOADING_INDICATION'); + expect(actionResult[5]).toStrictEqual({ payload: { name: 'CONVERT_TOKEN_TO_NFT', tokenAddress: 'tokenAddress', @@ -1600,24 +1654,32 @@ describe('Send Slice', () => { await store.dispatch(updateRecipientUserInput(newUserRecipientInput)); - expect(store.getActions()).toHaveLength(1); - expect(store.getActions()[0].type).toStrictEqual( + const actionResult = store.getActions(); + + expect(actionResult).toHaveLength(1); + expect(actionResult[0].type).toStrictEqual( 'send/updateRecipientUserInput', ); - expect(store.getActions()[0].payload).toStrictEqual( - newUserRecipientInput, - ); + expect(actionResult[0].payload).toStrictEqual(newUserRecipientInput); clock.tick(300); // debounce - expect(store.getActions()).toHaveLength(2); - expect(store.getActions()[1].type).toStrictEqual( + const actionResultAfterDebounce = store.getActions(); + expect(actionResultAfterDebounce).toHaveLength(3); + + expect(actionResultAfterDebounce[1]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: `sendFlow - user typed ${newUserRecipientInput} into recipient input field`, + }); + + expect(actionResultAfterDebounce[2].type).toStrictEqual( 'send/validateRecipientUserInput', ); - expect(store.getActions()[1].payload).toStrictEqual({ + expect(actionResultAfterDebounce[2].payload).toStrictEqual({ chainId: '', tokens: [], useTokenDetection: true, + userInput: newUserRecipientInput, tokenAddressList: ['0x514910771af9ca656af840dff83e8264ecf986ca'], }); }); @@ -1630,8 +1692,13 @@ describe('Send Slice', () => { await store.dispatch(useContactListForRecipientSearch()); const actionResult = store.getActions(); + expect(actionResult).toHaveLength(2); expect(actionResult).toStrictEqual([ + { + type: 'send/addHistoryEntry', + payload: 'sendFlow - user selected back to all on recipient screen', + }, { type: 'send/updateRecipientSearchMode', payload: RECIPIENT_SEARCH_MODES.CONTACT_LIST, @@ -1648,7 +1715,14 @@ describe('Send Slice', () => { const actionResult = store.getActions(); + expect(actionResult).toHaveLength(2); + expect(actionResult).toStrictEqual([ + { + type: 'send/addHistoryEntry', + payload: + 'sendFlow - user selected transfer to my accounts on recipient screen', + }, { type: 'send/updateRecipientSearchMode', payload: RECIPIENT_SEARCH_MODES.MY_ACCOUNTS, @@ -1890,20 +1964,24 @@ describe('Send Slice', () => { await store.dispatch(resetRecipientInput()); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(6); - expect(actionResult[0].type).toStrictEqual( + expect(actionResult).toHaveLength(7); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user cleared recipient input', + }); + expect(actionResult[1].type).toStrictEqual( 'send/updateRecipientUserInput', ); - expect(actionResult[0].payload).toStrictEqual(''); - expect(actionResult[1].type).toStrictEqual('send/updateRecipient'); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[1].payload).toStrictEqual(''); + expect(actionResult[2].type).toStrictEqual('send/updateRecipient'); + expect(actionResult[3].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[3].type).toStrictEqual( + expect(actionResult[4].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); - expect(actionResult[4].type).toStrictEqual('ENS/resetEnsResolution'); - expect(actionResult[5].type).toStrictEqual( + expect(actionResult[5].type).toStrictEqual('ENS/resetEnsResolution'); + expect(actionResult[6].type).toStrictEqual( 'send/validateRecipientUserInput', ); }); @@ -1927,10 +2005,14 @@ describe('Send Slice', () => { const actionResult = store.getActions(); const expectActionResult = [ + { + type: 'send/addHistoryEntry', + payload: 'sendFlow - user added custom hexData 0x1', + }, { type: 'send/updateUserInputHexData', payload: hexData }, ]; - expect(actionResult).toHaveLength(1); + expect(actionResult).toHaveLength(2); expect(actionResult).toStrictEqual(expectActionResult); }); }); @@ -1970,13 +2052,17 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(4); + expect(actionResult).toHaveLength(5); expect(actionResult[0].type).toStrictEqual('send/updateAmountMode'); expect(actionResult[1].type).toStrictEqual('send/updateAmountToMax'); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user toggled max mode on', + }); + expect(actionResult[3].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[3].type).toStrictEqual( + expect(actionResult[4].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -2014,13 +2100,17 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(4); + expect(actionResult).toHaveLength(5); expect(actionResult[0].type).toStrictEqual('send/updateAmountMode'); expect(actionResult[1].type).toStrictEqual('send/updateSendAmount'); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user toggled max mode off', + }); + expect(actionResult[3].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[3].type).toStrictEqual( + expect(actionResult[4].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); }); @@ -2045,8 +2135,13 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(1); - expect(actionResult[0].type).toStrictEqual('SHOW_CONF_TX_PAGE'); + expect(actionResult).toHaveLength(2); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: + 'sendFlow - user clicked next and transaction should be added to controller', + }); + expect(actionResult[1].type).toStrictEqual('SHOW_CONF_TX_PAGE'); }); it('should create actions for updateTransaction rejecting', async () => { @@ -2081,11 +2176,16 @@ describe('Send Slice', () => { const actionResult = store.getActions(); - expect(actionResult).toHaveLength(2); - expect(actionResult[0].type).toStrictEqual( + expect(actionResult).toHaveLength(3); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: + 'sendFlow - user clicked next and transaction should be updated in controller', + }); + expect(actionResult[1].type).toStrictEqual( 'UPDATE_TRANSACTION_EDITABLE_PARAMS', ); - expect(actionResult[1].type).toStrictEqual( + expect(actionResult[2].type).toStrictEqual( 'UPDATE_TRANSACTION_GAS_FEES', ); }); @@ -2133,9 +2233,13 @@ describe('Send Slice', () => { await store.dispatch(editTransaction(ASSET_TYPES.NATIVE, 1)); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(1); - expect(actionResult[0].type).toStrictEqual('send/editTransaction'); - expect(actionResult[0].payload).toStrictEqual({ + expect(actionResult).toHaveLength(2); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user clicked edit on transaction with id 1', + }); + expect(actionResult[1].type).toStrictEqual('send/editTransaction'); + expect(actionResult[1].payload).toStrictEqual({ address: '0xRecipientAddress', amount: '0xde0b6b3a7640000', data: '', @@ -2146,7 +2250,7 @@ describe('Send Slice', () => { nickname: '', }); - const action = actionResult[0]; + const action = actionResult[1]; const result = sendReducer(initialState, action); @@ -2254,9 +2358,25 @@ describe('Send Slice', () => { ), ); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(5); - expect(actionResult[0].type).toStrictEqual('send/updateAsset'); - expect(actionResult[0].payload).toStrictEqual({ + expect(actionResult).toHaveLength(9); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user clicked edit on transaction with id 1', + }); + expect(actionResult[1]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: `sendFlow - user set asset type to ${ASSET_TYPES.COLLECTIBLE}`, + }); + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset symbol to undefined', + }); + expect(actionResult[3]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset address to 0xTokenAddress', + }); + expect(actionResult[4].type).toStrictEqual('send/updateAsset'); + expect(actionResult[4].payload).toStrictEqual({ balance: '0x1', type: ASSET_TYPES.COLLECTIBLE, error: null, @@ -2270,18 +2390,17 @@ describe('Send Slice', () => { tokenId: '26847', }, }); - expect(actionResult[1].type).toStrictEqual( + expect(actionResult[5].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[2].type).toStrictEqual( + expect(actionResult[6].type).toStrictEqual( 'metamask/gas/SET_CUSTOM_GAS_LIMIT', ); - expect(actionResult[3].type).toStrictEqual( + expect(actionResult[7].type).toStrictEqual( 'send/computeEstimatedGasLimit/fulfilled', ); - expect(actionResult[4].type).toStrictEqual('send/editTransaction'); - - const action = actionResult[4]; + expect(actionResult[8].type).toStrictEqual('send/editTransaction'); + const action = actionResult[8]; const result = sendReducer(initialState, action); @@ -2383,11 +2502,27 @@ describe('Send Slice', () => { ); const actionResult = store.getActions(); - expect(actionResult).toHaveLength(7); - expect(actionResult[0].type).toStrictEqual('SHOW_LOADING_INDICATION'); - expect(actionResult[1].type).toStrictEqual('HIDE_LOADING_INDICATION'); - expect(actionResult[2].type).toStrictEqual('send/updateAsset'); - expect(actionResult[2].payload).toStrictEqual({ + expect(actionResult).toHaveLength(11); + expect(actionResult[0]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user clicked edit on transaction with id 1', + }); + expect(actionResult[1]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: `sendFlow - user set asset type to ${ASSET_TYPES.TOKEN}`, + }); + expect(actionResult[2]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset symbol to SYMB', + }); + expect(actionResult[3]).toMatchObject({ + type: 'send/addHistoryEntry', + payload: 'sendFlow - user set asset address to 0xTokenAddress', + }); + expect(actionResult[4].type).toStrictEqual('SHOW_LOADING_INDICATION'); + expect(actionResult[5].type).toStrictEqual('HIDE_LOADING_INDICATION'); + expect(actionResult[6].type).toStrictEqual('send/updateAsset'); + expect(actionResult[6].payload).toStrictEqual({ balance: '0x0', type: ASSET_TYPES.TOKEN, error: null, @@ -2398,17 +2533,17 @@ describe('Send Slice', () => { standard: 'ERC20', }, }); - expect(actionResult[3].type).toStrictEqual( + expect(actionResult[7].type).toStrictEqual( 'send/computeEstimatedGasLimit/pending', ); - expect(actionResult[4].type).toStrictEqual( + expect(actionResult[8].type).toStrictEqual( 'metamask/gas/SET_CUSTOM_GAS_LIMIT', ); - expect(actionResult[5].type).toStrictEqual( + expect(actionResult[9].type).toStrictEqual( 'send/computeEstimatedGasLimit/fulfilled', ); - expect(actionResult[6].type).toStrictEqual('send/editTransaction'); - expect(actionResult[6].payload).toStrictEqual({ + expect(actionResult[10].type).toStrictEqual('send/editTransaction'); + expect(actionResult[10].payload).toStrictEqual({ address: '0xrecipientaddress', // getting address from tokenData does .toLowerCase amount: '0x3a98', data: '', @@ -2419,7 +2554,7 @@ describe('Send Slice', () => { nickname: '', }); - const action = actionResult[6]; + const action = actionResult[10]; const result = sendReducer(initialState, action); diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.component.js b/ui/pages/send/send-content/add-recipient/add-recipient.component.js index 100d2877f..a46fa7a8b 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.component.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.component.js @@ -22,6 +22,7 @@ export default class AddRecipient extends Component { addressBookEntryName: PropTypes.string, contacts: PropTypes.array, nonContacts: PropTypes.array, + addHistoryEntry: PropTypes.func, useMyAccountsForRecipientSearch: PropTypes.func, useContactListForRecipientSearch: PropTypes.func, isUsingMyAccountsForRecipientSearch: PropTypes.bool, @@ -64,7 +65,10 @@ export default class AddRecipient extends Component { metricsEvent: PropTypes.func, }; - selectRecipient = (address, nickname = '') => { + selectRecipient = (address, nickname = '', type = 'user input') => { + this.props.addHistoryEntry( + `sendFlow - User clicked recipient from ${type}. address: ${address}, nickname ${nickname}`, + ); this.props.updateRecipient({ address, nickname }); }; @@ -109,11 +113,13 @@ export default class AddRecipient extends Component { content = this.renderExplicitAddress( recipient.address, recipient.nickname, + 'validated user input', ); } else if (ensResolution) { content = this.renderExplicitAddress( ensResolution, addressBookEntryName || userInput, + 'ENS resolution', ); } else if (isUsingMyAccountsForRecipientSearch) { content = this.renderTransfer(); @@ -127,12 +133,12 @@ export default class AddRecipient extends Component { ); } - renderExplicitAddress(address, name) { + renderExplicitAddress(address, name, type) { return (
this.selectRecipient(address, name)} + onClick={() => this.selectRecipient(address, name, type)} >
@@ -179,7 +185,9 @@ export default class AddRecipient extends Component { + this.selectRecipient(address, name, 'my accounts') + } />
); @@ -200,7 +208,9 @@ export default class AddRecipient extends Component { addressBook={addressBook} searchForContacts={this.searchForContacts.bind(this)} searchForRecents={this.searchForRecents.bind(this)} - selectRecipient={this.selectRecipient.bind(this)} + selectRecipient={(address, name) => + this.selectRecipient(address, name, 'contact list') + } > {ownedAccounts && ownedAccounts.length > 1 && !userInput && (