Merge remote-tracking branch 'origin/develop' into master-sync

feature/default_network_editable
Dan Miller 2 years ago
commit 7bea9848ab
  1. 74
      .circleci/config.yml
  2. 70
      .circleci/scripts/bundle-stats-commit.sh
  3. 1
      .eslintrc.js
  4. 1
      .metamaskrc.dist
  5. 10
      .storybook/3.COLORS.stories.mdx
  6. 125
      .storybook/4.BREAKPOINTS.stories.mdx
  7. 2
      .storybook/preview.js
  8. 394
      .storybook/test-data.js
  9. 3
      README.md
  10. 8
      app/_locales/de/messages.json
  11. 8
      app/_locales/el/messages.json
  12. 42
      app/_locales/en/messages.json
  13. 8
      app/_locales/es/messages.json
  14. 8
      app/_locales/es_419/messages.json
  15. 8
      app/_locales/fr/messages.json
  16. 8
      app/_locales/hi/messages.json
  17. 8
      app/_locales/id/messages.json
  18. 8
      app/_locales/ja/messages.json
  19. 8
      app/_locales/ko/messages.json
  20. 8
      app/_locales/ph/messages.json
  21. 8
      app/_locales/pt/messages.json
  22. 8
      app/_locales/pt_BR/messages.json
  23. 8
      app/_locales/ru/messages.json
  24. 8
      app/_locales/tl/messages.json
  25. 8
      app/_locales/tr/messages.json
  26. 8
      app/_locales/vi/messages.json
  27. 8
      app/_locales/zh/messages.json
  28. 8
      app/_locales/zh_CN/messages.json
  29. 8
      app/manifest/v3/_base.json
  30. 102
      app/scripts/app-init.js
  31. 14
      app/scripts/constants/contracts.js
  32. 14
      app/scripts/contentscript.js
  33. 6
      app/scripts/controllers/detect-tokens.js
  34. 28
      app/scripts/controllers/detect-tokens.test.js
  35. 17
      app/scripts/controllers/ens/ens.js
  36. 2
      app/scripts/controllers/ens/index.test.js
  37. 3
      app/scripts/controllers/incoming-transactions.js
  38. 8
      app/scripts/controllers/network/network.js
  39. 2
      app/scripts/controllers/transactions/index.test.js
  40. 74
      app/scripts/lib/account-tracker.js
  41. 3
      app/scripts/lib/buy-url.js
  42. 228
      app/scripts/lib/createRPCMethodTrackingMiddleware.js
  43. 217
      app/scripts/lib/createRPCMethodTrackingMiddleware.test.js
  44. 3
      app/scripts/lib/ens-ipfs/setup.js
  45. 3
      app/scripts/lib/network-store.js
  46. 55
      app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js
  47. 284
      app/scripts/metamask-controller.js
  48. 5
      development/build/etc.js
  49. 104
      development/build/scripts.js
  50. 170
      development/charts/flamegraph/chart/index.html
  51. 3117
      development/charts/flamegraph/lib/d3-flamegraph-tooltip.js
  52. 46
      development/charts/flamegraph/lib/d3-flamegraph.css
  53. 5719
      development/charts/flamegraph/lib/d3-flamegraph.js
  54. 67
      development/charts/table/index.html
  55. 18
      development/charts/table/jquery.min.js
  56. 12
      development/metamaskbot-build-announce.js
  57. 8
      jest.config.js
  58. 586
      lavamoat/browserify/beta/policy.json
  59. 586
      lavamoat/browserify/flask/policy.json
  60. 586
      lavamoat/browserify/main/policy.json
  61. 17
      package.json
  62. 5
      patches/abort-controller+3.0.0.patch
  63. 5
      shared/constants/app.js
  64. 4
      shared/constants/gas.js
  65. 14
      shared/constants/metametrics.js
  66. 10
      shared/constants/network.js
  67. 4
      shared/constants/phishing.js
  68. 33
      shared/constants/transaction.js
  69. 3
      shared/modules/fetch-with-timeout.js
  70. 8
      shared/modules/fetch-with-timeout.test.js
  71. 3
      shared/modules/rpc.utils.js
  72. 7
      shared/modules/transaction.utils.js
  73. 15
      shared/notifications/index.js
  74. 35
      test/e2e/benchmark.js
  75. 3
      test/e2e/fixtures/address-entry/state.json
  76. 3
      test/e2e/fixtures/connected-state/state.json
  77. 3
      test/e2e/fixtures/custom-rpc/state.json
  78. 3
      test/e2e/fixtures/custom-token/state.json
  79. 3
      test/e2e/fixtures/eip-1559-v2-dapp/state.json
  80. 3
      test/e2e/fixtures/eip-1559-v2/state.json
  81. 3
      test/e2e/fixtures/import-ui/state.json
  82. 3
      test/e2e/fixtures/imported-account/state.json
  83. 3
      test/e2e/fixtures/localization/state.json
  84. 3
      test/e2e/fixtures/metrics-enabled/state.json
  85. 3
      test/e2e/fixtures/navigate-transactions/state.json
  86. 3
      test/e2e/fixtures/onboarding/state.json
  87. 3
      test/e2e/fixtures/send-edit-v2/state.json
  88. 3
      test/e2e/fixtures/send-edit/state.json
  89. 3
      test/e2e/fixtures/special-settings/state.json
  90. 3
      test/e2e/fixtures/threebox-enabled/state.json
  91. 11
      test/e2e/helpers.js
  92. 140
      test/e2e/lavamoat-stats.js
  93. 29
      test/e2e/mock-e2e.js
  94. 119
      test/e2e/mv3-perf-stats/bundle-size.js
  95. 2
      test/e2e/mv3-perf-stats/index.js
  96. 111
      test/e2e/mv3-perf-stats/init-load-stats.js
  97. 111
      test/e2e/mv3-stats.js
  98. 3
      test/e2e/run-e2e-test.js
  99. 28
      test/e2e/seeder/ganache-contract-address-registry.js
  100. 88
      test/e2e/seeder/ganache-seeder.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -53,6 +53,9 @@ workflows:
- prep-build-test:
requires:
- prep-deps
- prep-build-test-mv3:
requires:
- prep-deps
- prep-build-test-flask:
requires:
- prep-deps
@ -133,6 +136,9 @@ workflows:
- benchmark:
requires:
- prep-build-test
- stats-module-load-init:
requires:
- prep-build-test-mv3
- job-publish-prerelease:
requires:
- prep-deps
@ -140,7 +146,9 @@ workflows:
- prep-build-beta
- prep-build-flask
- prep-build-storybook
- prep-build-test-mv3
- benchmark
- stats-module-load-init
- all-tests-pass
- job-publish-release:
filters:
@ -200,8 +208,8 @@ jobs:
- persist_to_workspace:
root: .
paths:
- node_modules
- build-artifacts
- node_modules
- build-artifacts
validate-lavamoat-config:
executor: node-browsers-medium-plus
@ -305,6 +313,26 @@ jobs:
- dist-test-flask
- builds-test-flask
prep-build-test-mv3:
executor: node-browsers-medium-plus
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Build extension in mv3 for testing
command: yarn build:test:mv3
- run:
name: Move test build to 'dist-test' to avoid conflict with production build
command: mv ./dist ./dist-test-mv3
- run:
name: Move test zips to 'builds-test' to avoid conflict with production build
command: mv ./builds ./builds-test-mv3
- persist_to_workspace:
root: .
paths:
- dist-test-mv3
- builds-test-mv3
prep-build-test:
executor: node-browsers-medium-plus
@ -419,7 +447,6 @@ jobs:
name: Validate release candidate changelog
command: yarn lint:changelog:rc
test-deps-audit:
executor: node-browsers
steps:
@ -574,6 +601,43 @@ jobs:
paths:
- test-artifacts
stats-module-load-init:
executor: node-browsers-medium-plus
steps:
- checkout
- run:
name: Re-Install Chrome
command: ./.circleci/scripts/chrome-install.sh
- attach_workspace:
at: .
- run:
name: Move test build to dist
command: mv ./dist-test-mv3 ./dist
- run:
name: Move test zips to builds
command: mv ./builds-test-mv3 ./builds
- run:
name: Run page load benchmark
command: |
mkdir -p test-artifacts/chrome/mv3
cp -R development/charts/flamegraph test-artifacts/chrome/mv3/initialisation
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/background
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/ui
cp -R development/charts/table test-artifacts/chrome/mv3/load_time
- run:
name: Run page load benchmark
command: yarn mv3:stats:chrome --out test-artifacts/chrome/mv3
- run:
name: Record bundle size at commit
command: ./.circleci/scripts/bundle-stats-commit.sh
- store_artifacts:
path: test-artifacts
destination: test-artifacts
- persist_to_workspace:
root: .
paths:
- test-artifacts
job-publish-prerelease:
executor: node-browsers
steps:
@ -648,7 +712,7 @@ jobs:
steps:
- add_ssh_keys:
fingerprints:
- "3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8"
- '3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8'
- checkout
- attach_workspace:
at: .
@ -670,7 +734,7 @@ jobs:
- run:
name: test:coverage:jest
command: yarn test:coverage:jest
- run:
- run:
name: Validate coverage thresholds
command: |
if ! git diff --exit-code jest.config.js development/jest.config.js; then

@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
if [[ -z "${GITHUB_TOKEN:-}" ]]
then
printf '%s\n' 'GITHUB_TOKEN environment variable must be set'
exit 1
elif [[ -z "${GITHUB_TOKEN_USER:-}" ]]
then
printf '%s\n' 'GITHUB_TOKEN_USER environment variable must be set'
exit 1
fi
printf '%s\n' 'Commit the manifest version and changelog if the manifest has changed'
if [[ "${CIRCLE_BRANCH}" != "develop" ]]
then
printf 'This is not develop branch'
exit 0
fi
mkdir temp
git config --global user.email "metamaskbot@users.noreply.github.com"
git config --global user.name "MetaMask Bot"
git clone git@github.com:MetaMask/extension_bundlesize_stats.git temp
if [[ -f "temp/stats/bundle_size_stats-${CIRCLE_SHA1}.json" ]]
then
printf 'Bundle size of the commit is already recorded'
cd ..
rm -rf temp
exit 0
fi
cp -R test-artifacts/chrome/mv3/bundle_size_stats.json temp/stats
echo " bundle_size_stats-${CIRCLE_SHA1}.json" >> temp/stats/fileList.txt
mv temp/stats/bundle_size_stats.json "temp/stats/bundle_size_stats-${CIRCLE_SHA1}.json"
cd temp
git add .
git commit --message "Bundle size at commit: ${CIRCLE_SHA1}"
repo_slug="$CIRCLE_PROJECT_USERNAME/extension_bundlesize_stats"
git push "https://$GITHUB_TOKEN_USER:$GITHUB_TOKEN@github.com/$repo_slug" main
cd ..
rm -rf temp

@ -8,6 +8,7 @@ module.exports = {
'app/vendor/**',
'builds/**/*',
'development/chromereload.js',
'development/charts/**',
'dist/**/*',
'node_modules/**/*',
],

@ -6,7 +6,6 @@ ONBOARDING_V2=
SWAPS_USE_DEV_APIS=
COLLECTIBLES_V1=
TOKEN_DETECTION_V2=
ADD_POPULAR_NETWORKS=
; Set this to test changes to the phishing warning page.
PHISHING_WARNING_PAGE_URL=

@ -1,20 +1,12 @@
import { Meta } from '@storybook/addon-docs';
import ActionaleMessage from '../ui/components/ui/actionable-message';
import designTokenDiagramImage from './images/design.token.graphic.svg';
<Meta title="Design Tokens / Color" />
<Meta title="Foundations / Color" />
# Color
Color is used to express style and communicate meaning.
<ActionaleMessage
type="warning"
message="We are in the process of consolidating all of our colors, making them accessible and enabling theming. Many of the colors used throughout the codebase are deprecated please follow the guide below to ensure you are using the correct colors when building MetaMask UI"
/>
<br />
## Design tokens
We are importing design tokens as CSS variables from [@metamask/design-tokens](https://github.com/MetaMask/design-tokens) repo to help consolidate colors and enable theming across all MetaMask products.

@ -0,0 +1,125 @@
import { Meta } from '@storybook/addon-docs';
<Meta title="Foundations / Breakpoints" />
# Breakpoints
Breakpoints are used for responsive layout
## Screen Sizes
There are 4 screen sizes that make up the breakpoints for the MetaMask extension
- base: `0px`
- sm: `576px`
- md: `768px`
- lg: `1280px`
### SCSS
There are Sass variables and mixins available for use for both min and max screens sizes
### Variables
```css
$screen-sm-max /* 575px */
$screen-md-max /* 767px */
$screen-lg-max /* 1279px */
$screen-sm-min /* 576px */
$screen-md-min /* 768px */
$screen-lg-min /* 1280px */
```
### Mixins
```css
/* Max screen size */
@include screen-sm-max {
/* equivalent css @media screen and (max-width: 575px) */
}
@include screen-md-max {
/* equivalent css @media screen and (max-width: 767px) */
}
@include screen-lg-max {
/* equivalent css @media screen and (max-width: 1279px) */
}
/* Min screen size */
@include screen-sm-min {
/* equivalent css @media screen and (min-width: 576px) */
}
@include screen-md-min {
/* equivalent css @media screen and (min-width: 768px) */
}
@include screen-lg-min {
/* equivalent css @media screen and (min-width: 1280px) */
}
```
Migrating from the old sass variables to the new mixins looks like this
```css
/* Max width */
/* Instead of the media query and sass variable */
@media screen and (max-width: $break-small) {
right: 16px;
}
/* Use the sass mixin */
@include screen-sm-max {
right: 16px;
}
/* Min width */
/* Instead of the media query and sass variable */
@media screen and (min-width: $break-large) {
left: 16px;
}
/* Use the sass mixin */
@include screen-sm-min {
left: 16px;
}
```
## Takeaways
- Try to avoid using static media queries in your code.
- Try to use the provided SCSS mixins
### ❌ Don't do this
Don't use static media queries in your code.
```css
/**
* Don't do this
* Static media queries create inconsistency and could break the UI if we want to update them in future
**/
.account-menu {
@media screen and (min-width: 769px) {
right: calc((100vw - 80vw) / 2);
}
@media screen and (min-width: 1281px) {
right: calc((100vw - 65vw) / 2);
}
}
```
### ✅ Do this
Do use the provided Sass mixins
```css
.account-menu {
@include screen-md-min {
right: calc((100vw - 80vw) / 2);
}
@include screen-lg-min {
right: calc((100vw - 65vw) / 2);
}
}
```

@ -30,7 +30,7 @@ addParameters({
storySort: {
order: [
'Getting Started',
'Design Tokens',
'Foundations',
'Components',
['UI', 'App'],
'Pages',

@ -1,3 +1,4 @@
import { draftTransactionInitialState } from '../ui/ducks/send';
const state = {
invalidCustomNetwork: {
state: 'CLOSED',
@ -15,99 +16,99 @@ const state = {
},
networkList: [
{
blockExplorerUrl: "https://etherscan.io",
chainId: "0x1",
blockExplorerUrl: 'https://etherscan.io',
chainId: '0x1',
iconColor: 'var(--mainnet)',
isATestNetwork: false,
labelKey: "mainnet",
providerType: "mainnet",
rpcUrl: "https://mainnet.infura.io/v3/",
ticker: "ETH",
labelKey: 'mainnet',
providerType: 'mainnet',
rpcUrl: 'https://mainnet.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://ropsten.etherscan.io",
chainId: "0x3",
blockExplorerUrl: 'https://ropsten.etherscan.io',
chainId: '0x3',
iconColor: 'var(--ropsten)',
isATestNetwork: true,
labelKey: "ropsten",
providerType: "ropsten",
rpcUrl: "https://ropsten.infura.io/v3/",
ticker: "ETH",
labelKey: 'ropsten',
providerType: 'ropsten',
rpcUrl: 'https://ropsten.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://rinkeby.etherscan.io",
chainId: "0x4",
blockExplorerUrl: 'https://rinkeby.etherscan.io',
chainId: '0x4',
iconColor: 'var(--rinkeby)',
isATestNetwork: true,
labelKey: "rinkeby",
providerType: "rinkeby",
rpcUrl: "https://rinkeby.infura.io/v3/",
ticker: "ETH",
labelKey: 'rinkeby',
providerType: 'rinkeby',
rpcUrl: 'https://rinkeby.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://goerli.etherscan.io",
chainId: "0x5",
blockExplorerUrl: 'https://goerli.etherscan.io',
chainId: '0x5',
iconColor: 'var(--goerli)',
isATestNetwork: true,
labelKey: "goerli",
providerType: "goerli",
rpcUrl: "https://goerli.infura.io/v3/",
ticker: "ETH",
labelKey: 'goerli',
providerType: 'goerli',
rpcUrl: 'https://goerli.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://kovan.etherscan.io",
chainId: "0x2a",
blockExplorerUrl: 'https://kovan.etherscan.io',
chainId: '0x2a',
iconColor: 'var(--kovan)',
isATestNetwork: true,
labelKey: "kovan",
providerType: "kovan",
rpcUrl: "https://kovan.infura.io/v3/",
ticker: "ETH",
labelKey: 'kovan',
providerType: 'kovan',
rpcUrl: 'https://kovan.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "",
chainId: "0x539",
blockExplorerUrl: '',
chainId: '0x539',
iconColor: 'var(--localhost)',
isATestNetwork: true,
label: "Localhost 8545",
providerType: "rpc",
rpcUrl: "http://localhost:8545",
ticker: "ETH",
label: 'Localhost 8545',
providerType: 'rpc',
rpcUrl: 'http://localhost:8545',
ticker: 'ETH',
},
{
blockExplorerUrl: "https://bscscan.com",
chainId: "0x38",
blockExplorerUrl: 'https://bscscan.com',
chainId: '0x38',
iconColor: 'var(--localhost)',
isATestNetwork: false,
label: "Binance Smart Chain",
providerType: "rpc",
rpcUrl: "https://bsc-dataseed.binance.org/",
ticker: "BNB",
label: 'Binance Smart Chain',
providerType: 'rpc',
rpcUrl: 'https://bsc-dataseed.binance.org/',
ticker: 'BNB',
},
{
blockExplorerUrl: "https://cchain.explorer.avax.network/",
chainId: "0xa86a",
blockExplorerUrl: 'https://cchain.explorer.avax.network/',
chainId: '0xa86a',
iconColor: 'var(--localhost)',
isATestNetwork: false,
label: "Avalanche",
providerType: "rpc",
rpcUrl: "https://api.avax.network/ext/bc/C/rpc",
ticker: "AVAX",
label: 'Avalanche',
providerType: 'rpc',
rpcUrl: 'https://api.avax.network/ext/bc/C/rpc',
ticker: 'AVAX',
},
{
blockExplorerUrl: "https://polygonscan.com",
chainId: "0x89",
blockExplorerUrl: 'https://polygonscan.com',
chainId: '0x89',
iconColor: 'var(--localhost)',
isATestNetwork: false,
label: "Polygon",
providerType: "rpc",
rpcUrl: "https://polygon-rpc.com",
ticker: "MATIC",
label: 'Polygon',
providerType: 'rpc',
rpcUrl: 'https://polygon-rpc.com',
ticker: 'MATIC',
},
],
metamask: {
@ -132,7 +133,7 @@ const state = {
'0x',
],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0xc00e94cb662c3520282e6f5717214004a7f26888': {
address: '0xc00e94cb662c3520282e6f5717214004a7f26888',
@ -153,23 +154,18 @@ const state = {
'0x',
],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0xfffffffff15abf397da76f1dcc1a1604f45126db': {
address: '0xfffffffff15abf397da76f1dcc1a1604f45126db',
symbol: 'FSW',
decimals: 18,
name: 'Falconswap',
iconUrl: 'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184',
aggregators: [
'CoinGecko',
'1inch',
'Paraswap',
'Zapper',
'Zerion',
],
iconUrl:
'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184',
aggregators: ['CoinGecko', '1inch', 'Paraswap', 'Zapper', 'Zerion'],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f': {
address: '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f',
@ -192,70 +188,70 @@ const state = {
'0x',
],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0x6b175474e89094c44da98b954eedeac495271d0f': {
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
symbol: 'META',
decimals: 18,
image: 'metamark.svg',
unlisted: false
unlisted: false,
},
'0xB8c77482e45F1F44dE1745F52C74426C631bDD52': {
address: '0xB8c77482e45F1F44dE1745F52C74426C631bDD52',
symbol: '0X',
decimals: 18,
image: '0x.svg',
unlisted: false
unlisted: false,
},
'0x1f9840a85d5af5bf1d1762f925bdaddc4201f984': {
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
symbol: 'AST',
decimals: 18,
image: 'ast.png',
unlisted: false
unlisted: false,
},
'0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2': {
address: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
symbol: 'BAT',
decimals: 18,
image: 'BAT_icon.svg',
unlisted: false
unlisted: false,
},
'0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1': {
address: '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1',
symbol: 'CVL',
decimals: 18,
image: 'CVL_token.svg',
unlisted: false
unlisted: false,
},
'0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e': {
address: '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e',
symbol: 'GLA',
decimals: 18,
image: 'gladius.svg',
unlisted: false
unlisted: false,
},
'0x467Bccd9d29f223BcE8043b84E8C8B282827790F': {
address: '0x467Bccd9d29f223BcE8043b84E8C8B282827790F',
symbol: 'GNO',
decimals: 18,
image: 'gnosis.svg',
unlisted: false
unlisted: false,
},
'0xff20817765cb7f73d4bde2e66e067e58d11095c2': {
address: '0xff20817765cb7f73d4bde2e66e067e58d11095c2',
symbol: 'OMG',
decimals: 18,
image: 'omg.jpg',
unlisted: false
unlisted: false,
},
'0x8e870d67f660d95d5be530380d0ec0bd388289e1': {
address: '0x8e870d67f660d95d5be530380d0ec0bd388289e1',
symbol: 'WED',
decimals: 18,
image: 'wed.png',
unlisted: false
unlisted: false,
},
},
networkDetails: {
@ -281,83 +277,84 @@ const state = {
swapsFeatureIsLive: false,
swapsQuoteRefreshTime: 60000,
},
"snapStates": {},
"snaps": {
"local:http://localhost:8080/": {
"enabled": true,
"id": "local:http://localhost:8080/",
"initialPermissions": {
"snap_confirm": {}
snapStates: {},
snaps: {
'local:http://localhost:8080/': {
enabled: true,
id: 'local:http://localhost:8080/',
initialPermissions: {
snap_confirm: {},
},
"manifest": {
"description": "An example MetaMask Snap.",
"initialPermissions": {
"snap_confirm": {}
manifest: {
description: 'An example MetaMask Snap.',
initialPermissions: {
snap_confirm: {},
},
"manifestVersion": "0.1",
"proposedName": "MetaMask Example Snap",
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/snaps-skunkworks.git"
manifestVersion: '0.1',
proposedName: 'MetaMask Example Snap',
repository: {
type: 'git',
url: 'https://github.com/MetaMask/snaps-skunkworks.git',
},
"source": {
"location": {
"npm": {
"filePath": "dist/bundle.js",
"iconPath": "images/icon.svg",
"packageName": "@metamask/example-snap",
"registry": "https://registry.npmjs.org/"
}
source: {
location: {
npm: {
filePath: 'dist/bundle.js',
iconPath: 'images/icon.svg',
packageName: '@metamask/example-snap',
registry: 'https://registry.npmjs.org/',
},
},
"shasum": "3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE="
shasum: '3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE=',
},
"version": "0.6.0"
version: '0.6.0',
},
"permissionName": "wallet_snap_local:http://localhost:8080/",
"sourceCode": "(...)",
"status": "stopped",
"svgIcon": "<svg>...</svg>",
"version": "0.6.0"
},
"Filecoin Snap": {
"enabled": true,
"id": "npm:http://localhost:8080/",
"initialPermissions": {
"snap_confirm": {},
"eth_accounts": {},
"snap_manageState": {},
permissionName: 'wallet_snap_local:http://localhost:8080/',
sourceCode: '(...)',
status: 'stopped',
svgIcon: '<svg>...</svg>',
version: '0.6.0',
},
'Filecoin Snap': {
enabled: true,
id: 'npm:http://localhost:8080/',
initialPermissions: {
snap_confirm: {},
eth_accounts: {},
snap_manageState: {},
},
"manifest": {
"description": "This swap provides developers everywhere access to an entirely new data storage paradigm, even letting your programs store data autonomously. Learn more.",
"initialPermissions": {
"snap_confirm": {},
"eth_accounts": {},
"snap_manageState": {},
manifest: {
description:
'This swap provides developers everywhere access to an entirely new data storage paradigm, even letting your programs store data autonomously. Learn more.',
initialPermissions: {
snap_confirm: {},
eth_accounts: {},
snap_manageState: {},
},
"manifestVersion": "0.1",
"proposedName": "Filecoin Snap",
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/snaps-skunkworks.git"
manifestVersion: '0.1',
proposedName: 'Filecoin Snap',
repository: {
type: 'git',
url: 'https://github.com/MetaMask/snaps-skunkworks.git',
},
"source": {
"location": {
"npm": {
"filePath": "dist/bundle.js",
"iconPath": "images/icon.svg",
"packageName": "@metamask/example-snap",
"registry": "https://registry.npmjs.org/"
}
source: {
location: {
npm: {
filePath: 'dist/bundle.js',
iconPath: 'images/icon.svg',
packageName: '@metamask/example-snap',
registry: 'https://registry.npmjs.org/',
},
},
"shasum": "3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE="
shasum: '3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE=',
},
"version": "0.6.0"
version: '0.6.0',
},
"permissionName": "wallet_snap_npm:http://localhost:8080/",
"sourceCode": "(...)",
"status": "stopped",
"svgIcon": "<svg>...</svg>",
"version": "0.6.0"
permissionName: 'wallet_snap_npm:http://localhost:8080/',
sourceCode: '(...)',
status: 'stopped',
svgIcon: '<svg>...</svg>',
version: '0.6.0',
},
},
accountArray: [
@ -486,32 +483,46 @@ const state = {
],
detectedTokens: [
{
address: "0x514910771AF9Ca656af840dff83E8264EcF986CA",
address: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
decimals: 18,
symbol: "LINK",
image: "https://crypto.com/price/coin-data/icon/LINK/color_icon.png",
aggregators:[
"coinGecko","oneInch","paraswap","zapper","zerion"
]
symbol: 'LINK',
image: 'https://crypto.com/price/coin-data/icon/LINK/color_icon.png',
aggregators: ['coinGecko', 'oneInch', 'paraswap', 'zapper', 'zerion'],
},
{
address: "0xc00e94Cb662C3520282E6f5717214004A7f26888",
address: '0xc00e94Cb662C3520282E6f5717214004A7f26888',
decimals: 18,
symbol: "COMP",
image: "https://crypto.com/price/coin-data/icon/COMP/color_icon.png",
aggregators:[
"bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"
]
symbol: 'COMP',
image: 'https://crypto.com/price/coin-data/icon/COMP/color_icon.png',
aggregators: [
'bancor',
'cmc',
'cryptocom',
'coinGecko',
'oneInch',
'paraswap',
'pmm',
'zapper',
'zerion',
'zeroEx',
],
},
{
address: "0xfffffffFf15AbF397dA76f1dcc1A1604F45126DB",
address: '0xfffffffFf15AbF397dA76f1dcc1A1604F45126DB',
decimals: 18,
symbol: "FSW",
image: "https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184",
aggregators:[
"aave", "cmc","coinGecko","oneInch","paraswap","zapper","zerion"
]
}
symbol: 'FSW',
image:
'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184',
aggregators: [
'aave',
'cmc',
'coinGecko',
'oneInch',
'paraswap',
'zapper',
'zerion',
],
},
],
pendingTokens: {},
customNonceValue: '',
@ -559,18 +570,18 @@ const state = {
swapsWelcomeMessageHasBeenShown: true,
defaultHomeActiveTabName: 'Assets',
provider: {
type: 'ropsten',
type: 'rinkeby',
ticker: 'ETH',
nickname: '',
rpcUrl: '',
chainId: '0x3',
chainId: '0x4',
},
previousProviderStore: {
type: 'ropsten',
type: 'rinkeby',
ticker: 'ETH',
nickname: '',
rpcUrl: '',
chainId: '0x3',
chainId: '0x4',
},
network: '3',
accounts: {
@ -1304,7 +1315,7 @@ const state = {
subjects: {
'https://app.uniswap.org': {
permissions: {
'eth_accounts': {
eth_accounts: {
invoker: 'https://app.uniswap.org',
parentCapability: 'eth_accounts',
id: 'a7342e4b-beae-4525-a36c-c0635fd03359',
@ -1318,14 +1329,14 @@ const state = {
},
},
},
"local:http://localhost:8080/": {
'local:http://localhost:8080/': {
permissions: {
'snap_confirm': {
invoker: "local:http://localhost:8080/",
snap_confirm: {
invoker: 'local:http://localhost:8080/',
parentCapability: 'snap_confirm',
id: 'a7342F4b-beae-4525-a36c-c0635fd03359',
date: 1620710693178,
caveats: []
caveats: [],
},
},
},
@ -1423,30 +1434,30 @@ const state = {
pendingApprovals: {},
pendingApprovalCount: 0,
subjectMetadata: {
"http://localhost:8080": {
'http://localhost:8080': {
extensionId: null,
iconUrl: null,
name: "Hello, Snaps!",
origin: "http://localhost:8080",
subjectType: "website"
name: 'Hello, Snaps!',
origin: 'http://localhost:8080',
subjectType: 'website',
},
"https://metamask.github.io": {
'https://metamask.github.io': {
extensionId: null,
iconUrl: null,
name: "Snaps Iframe Execution Environment",
origin: "https://metamask.github.io",
subjectType: "website"
name: 'Snaps Iframe Execution Environment',
origin: 'https://metamask.github.io',
subjectType: 'website',
},
"local:http://localhost:8080/": {
'local:http://localhost:8080/': {
extensionId: null,
iconUrl: null,
name: "MetaMask Example Snap",
origin: "local:http://localhost:8080/",
subjectType: "snap",
svgIcon: "<svg>...</svg>",
version: "0.6.0"
}
}
name: 'MetaMask Example Snap',
origin: 'local:http://localhost:8080/',
subjectType: 'snap',
svgIcon: '<svg>...</svg>',
version: '0.6.0',
},
},
},
appState: {
shouldClose: false,
@ -1455,7 +1466,14 @@ const state = {
open: false,
modalState: {
name: null,
props: {},
props: {
token: {
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D',
symbol: 'DAI',
decimals: 18,
},
history: {},
},
},
previousModalState: {
name: null,
@ -1507,6 +1525,12 @@ const state = {
amount: {
error: 'amount',
},
currentTransactionUUID: 'test-uuid',
draftTransactions: {
'test-uuid': {
...draftTransactionInitialState,
},
},
},
confirmTransaction: {
txData: {

@ -14,7 +14,7 @@ To learn how to contribute to the MetaMask project itself, visit our [Internal D
## Building locally
- Install [Node.js](https://nodejs.org) version 14
- Install [Node.js](https://nodejs.org) version 16
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
- Install [Yarn](https://yarnpkg.com/en/docs/install)
- Install dependencies: `yarn setup` (not the usual install command)
@ -118,3 +118,4 @@ Whenever you change dependencies (adding, removing, or updating, either in `pack
- [How to generate a visualization of this repository's development](./development/gource-viz.sh)
[1]: http://www.nomnoml.com/#view/%5B%3Cactor%3Euser%5D%0A%0A%5Bmetamask-ui%7C%0A%20%20%20%5Btools%7C%0A%20%20%20%20%20react%0A%20%20%20%20%20redux%0A%20%20%20%20%20thunk%0A%20%20%20%20%20ethUtils%0A%20%20%20%20%20jazzicon%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20account-detail%0A%20%20%20%20%20accounts%0A%20%20%20%20%20locked-screen%0A%20%20%20%20%20restore-vault%0A%20%20%20%20%20identicon%0A%20%20%20%20%20config%0A%20%20%20%20%20info%0A%20%20%20%5D%0A%20%20%20%5Breducers%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20metamask%0A%20%20%20%20%20identities%0A%20%20%20%5D%0A%20%20%20%5Bactions%7C%0A%20%20%20%20%20%5BbackgroundConnection%5D%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%5D%3A-%3E%5Bactions%5D%0A%20%20%20%5Bactions%5D%3A-%3E%5Breducers%5D%0A%20%20%20%5Breducers%5D%3A-%3E%5Bcomponents%5D%0A%5D%0A%0A%5Bweb%20dapp%7C%0A%20%20%5Bui%20code%5D%0A%20%20%5Bweb3%5D%0A%20%20%5Bmetamask-inpage%5D%0A%20%20%0A%20%20%5B%3Cactor%3Eui%20developer%5D%0A%20%20%5Bui%20developer%5D-%3E%5Bui%20code%5D%0A%20%20%5Bui%20code%5D%3C-%3E%5Bweb3%5D%0A%20%20%5Bweb3%5D%3C-%3E%5Bmetamask-inpage%5D%0A%5D%0A%0A%5Bmetamask-background%7C%0A%20%20%5Bprovider-engine%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bid%20store%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%3E%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%3C-%3E%5Bid%20store%5D%0A%20%20%5Bconfig%20manager%7C%0A%20%20%20%20%5Brpc%20configuration%5D%0A%20%20%20%20%5Bencrypted%20keys%5D%0A%20%20%20%20%5Bwallet%20nicknames%5D%0A%20%20%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%5Bconfig%20manager%5D%0A%20%20%5Bid%20store%5D%3C-%3E%5Bconfig%20manager%5D%0A%5D%0A%0A%5Buser%5D%3C-%3E%5Bmetamask-ui%5D%0A%0A%5Buser%5D%3C%3A--%3A%3E%5Bweb%20dapp%5D%0A%0A%5Bmetamask-contentscript%7C%0A%20%20%5Bplugin%20restart%20detector%5D%0A%20%20%5Brpc%20passthrough%5D%0A%5D%0A%0A%5Brpc%20%7C%0A%20%20%5Bethereum%20blockchain%20%7C%0A%20%20%20%20%5Bcontracts%5D%0A%20%20%20%20%5Baccounts%5D%0A%20%20%5D%0A%5D%0A%0A%5Bweb%20dapp%5D%3C%3A--%3A%3E%5Bmetamask-contentscript%5D%0A%5Bmetamask-contentscript%5D%3C-%3E%5Bmetamask-background%5D%0A%5Bmetamask-background%5D%3C-%3E%5Bmetamask-ui%5D%0A%5Bmetamask-background%5D%3C-%3E%5Brpc%5D%0A

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "6M+ Benutzern beitreten um MetaMask zu verbessern"
},
"mismatchedChain": {
"message": "Die Netzwerkdetails für diese Ketten-ID stimmen nicht mit unseren Aufzeichnungen überein. Wir empfehlen Ihnen $1, bevor Sie fortfahren.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "die Netzwerkdetails überprüfen",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Dieses benutzerdefinierte Netzwerk ist nicht erkannt. Wir empfehlen, dass Sie $1 bevor Sie fortfahren",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "die Netzwerkdetails überprüfen",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Verwenden von Sammelbaren (ERC-721) Token wird derzeit nicht unterstützt",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Συμμετάσχετε σε 6εκ+ χρήστες για να βελτιώσετε το MetaMask"
},
"mismatchedChain": {
"message": "Οι λεπτομέρειες δικτύου για αυτό το αναγνωριστικό αλυσίδας δεν ταιριάζουν με τις εγγραφές μας. Σας συνιστούμε να $1 πριν συνεχίσετε.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "επαληθεύστε τα στοιχεία δικτύου",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Αυτό το προσαρμοσμένο δίκτυο δεν αναγνωρίζεται. Σας συνιστούμε να $1 πριν προχωρήσετε",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "επαληθεύστε τα στοιχεία δικτύου",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Η αποστολή συλλεκτικών (ERC-721) δεν υποστηρίζεται προς το παρόν",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1638,6 +1638,9 @@
"invalidSeedPhrase": {
"message": "Invalid Secret Recovery Phrase"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Invalid input! Secret Recovery Phrase is case sensitive."
},
"ipfsGateway": {
"message": "IPFS Gateway"
},
@ -1909,14 +1912,23 @@
"metametricsTitle": {
"message": "Join 6M+ users to improve MetaMask"
},
"mismatchedChain": {
"message": "The network details for this chain ID do not match our records. We recommend that you $1 before proceeding.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verify the network details",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "We recommend that you $1 before proceeding.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "According to our record the network name may not correctly match this chain ID."
},
"mismatchedNetworkSymbol": {
"message": "The submitted currency symbol does not match what we expect for this chain ID."
},
"mismatchedRpcUrl": {
"message": "According to our records the submitted RPC URL value does not match a known provider for this chain ID."
},
"missingNFT": {
"message": "Don't see your NFT?"
},
@ -2190,6 +2202,16 @@
"notifications12Title": {
"message": "Wen dark mode? Now dark mode! 🕶🦊"
},
"notifications13ActionText": {
"message": "Show custom network list"
},
"notifications13Description": {
"message": "You can now add the following popular custom networks easily: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm and Polygon! To enable this feature, go to Settings -> Experimental and turn \"Show custom network list\" on!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Add Popular Networks"
},
"notifications1Description": {
"message": "MetaMask Mobile users can now swap tokens inside their mobile wallet. Scan the QR code to get the mobile app and start swapping.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -3195,7 +3217,7 @@
"message": "Swap would have failed"
},
"stxCancelledDescription": {
"message": "Your transaction would have failed and was canceled to protect you from paying unnecessary gas fees."
"message": "Your transaction would have failed and was cancelled to protect you from paying unnecessary gas fees."
},
"stxCancelledSubDescription": {
"message": "Try your swap again. We’ll be here to protect you against similar risks next time."
@ -3261,10 +3283,10 @@
"message": "A transaction has been successful but we’re unsure what it is. This may be due to submitting another transaction while this swap was processing."
},
"stxUserCancelled": {
"message": "Swap canceled"
"message": "Swap cancelled"
},
"stxUserCancelledDescription": {
"message": "Your transaction has been canceled and you did not pay any unnecessary gas fees."
"message": "Your transaction has been cancelled and you did not pay any unnecessary gas fees."
},
"stxYouCanOptOut": {
"message": "You can opt-out in advanced settings any time."
@ -3933,13 +3955,9 @@
"message": "The decentralized web awaits"
},
"unrecognizedChain": {
"message": "This custom network is not recognized. We recommend that you $1 before proceeding",
"message": "This custom network is not recognized",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verify the network details",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Sending collectible (ERC-721) tokens is not currently supported",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Únase a más de 6 millones de usuarios para mejorar MetaMask"
},
"mismatchedChain": {
"message": "Los detalles de la red de este identificador de cadena no coinciden con nuestros registros. Antes de continuar, le recomendamos que $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "No se reconoce esta red personalizada. Antes de continuar, le recomendamos que $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1643,10 +1643,6 @@
"metametricsTitle": {
"message": "Únase a más de 6 millones de usuarios para mejorar MetaMask"
},
"mismatchedChain": {
"message": "Los detalles de la red de este ID de cadena no coinciden con nuestros registros. Antes de continuar, le recomendamos que $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3215,10 +3211,6 @@
"message": "No se reconoce esta red personalizada. Antes de continuar, le recomendamos que $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Rejoignez plus de 6 M d’utilisateurs pour améliorer MetaMask"
},
"mismatchedChain": {
"message": "Les détails du réseau pour cet ID de chaîne ne correspondent pas à nos registres. Nous vous recommandons de $1 avant de poursuivre.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "vérifier les détails du réseau",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Ce réseau personnalisé n’est pas reconnu. Nous vous recommandons de $1 avant de continuer",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "vérifier les détails du réseau",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "L’envoi de jetons collectibles (ERC-721) n’est pas pris en charge actuellement",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "MetaMask कहतर बनिए 6M+ उपयगकर"
},
"mismatchedChain": {
"message": "इस चन ID किए नटवरक विवरण हमिड सल नह। हम अन करति आप आग बढ पहल $1।",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "नटवरक विवरण सतित कर",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "यह कसटम नटवरक पहच नह गय। हम अन करति आप आग बढ पहल $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "नटवरक विवरण सतित कर",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "वरतमन मरहणय (ERC-721) टकन भजन समरित नह",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Bergabunglah bersama 6 Jt+ pengguna untuk meningkatkan MetaMask"
},
"mismatchedChain": {
"message": "Detail jaringan untuk ID rantai ini tidak cocok dengan catatan kami. Kami menyarankan agar Anda $1 sebelum melanjutkan.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "memverifikasi detail jaringan",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Jaringan kustom ini tidak dikenali. Kami menyarankan agar Anda $1 sebelum melanjutkan",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "memverifikasi detail jaringan",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Tidak mendukung pengiriman token koleksi (ERC-721) untuk saat ini",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "6百万人以上のユーザーと共に、MetaMaskの改善にご協力ください"
},
"mismatchedChain": {
"message": "このチェーンIDのネットワーク詳細が、レコードと一致しません。続行する前に$1をお勧めします。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "ネットワークの詳細の確認",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "このカスタムネットワークは認識されません。続行する前に$1をお勧めします",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "ネットワークの詳細の確認",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "コレクティブル (ERC-721) トークンの送信は現在サポートされていません",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "6백만 명 이상의 사용자와 함께 MetaMask 기능 향상에 동참하세요."
},
"mismatchedChain": {
"message": "이 체인 ID의 네트워크 세부 정보가 기록과 일치하지 않습니다. 진행하기 전에 $1을(를) 권장합니다.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "네트워크 세부 정보 검증",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "이 맞춤형 네트워크는 인식되지 않습니다. 진행하기 전에 $1을(를) 권장합니다.",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "네트워크 세부 정보 검증",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "수집 가능한(ERC-721) 토큰 전송은 현재 지원되지 않습니다.",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1039,10 +1039,6 @@
"metametricsOptInDescription": {
"message": "Gustong kunin ng MetaMask ang data ng paggamit para mas maunawaan kung paano ginagamit ng mga user namin ang extension. Gagamitin ang data na ito para patuloy na mapahusay ang kakayahang magamit at karanasan ng user sa paggamit ng produkto namin at Ethereum ecosystem."
},
"mismatchedChain": {
"message": "Ang mga detalye ng network para sa chain ID na ito ay hindi tumutugma sa aming mga record. Inirerekomenda naming $1 ka bago magpatuloy.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -2161,10 +2157,6 @@
"message": "Hindi kinikilala ang custom na network na ito. Inirerekomenda naming $1 ka bago magpatuloy",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"updatedWithDate": {
"message": "Na-update noong $1"
},

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Junte-se a mais de 6 milhões de usuários para melhorar a MetaMask"
},
"mismatchedChain": {
"message": "Os detalhes da rede para esse ID da cadeia não correspondem aos dos nossos registros. Recomendamos que você $1 antes de continuar.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Essa rede personalizada não foi reconhecida. Recomendamos que você $1 antes de continuar",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1627,10 +1627,6 @@
"metametricsTitle": {
"message": "Junte-se a mais de 6 milhões de usuários para melhorar a MetaMask"
},
"mismatchedChain": {
"message": "Os detalhes da rede para esse ID da cadeia não correspondem aos dos nossos registros. Recomendamos que você $1 antes de continuar.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3199,10 +3195,6 @@
"message": "Essa rede personalizada não foi reconhecida. Recomendamos que você $1 antes de continuar",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Присоединяйтесь к более чем 6 млн пользователей, чтобы улучшить MetaMask"
},
"mismatchedChain": {
"message": "Сведения о сети для этого ID цепочки не совпадают с указанными в записях. Мы рекомендуем $1 до того, как продолжить.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "проверить сведения о сети",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Эта пользовательская сеть не распознана. Мы рекомендуем $1, прежде чем продолжить",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "проверить сведения о сети",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Отправка коллекционных активов (ERC-721) сейчас не поддерживается",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Sumali sa 6M+ user upang mapabuti ang MetaMask"
},
"mismatchedChain": {
"message": "Ang mga detalye ng network para sa chain ID na ito ay hindi tumutugma sa aming mga talaan. Inirerekomenda namin na $1 ka bago magpatuloy.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Hindi nakikilala ang custom network na ito. Nirerekomenda namin na ikaw ay $1 bago magpatuloy",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Ang pagpapadala ng collectible (ERC-721) token ay kasalukuyang hindi magagamit",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "MetaMask'i geliştirmek için 6 milyondan fazla kullanıcıya katılın"
},
"mismatchedChain": {
"message": "Bu zincir kimliği için ağ ayrıntıları kayıtlarımızla uyumlu değil. Devam etmeden önce şunu yapmanızı öneriyoruz: $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "ağ bilgilerini doğrula",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Bu özel ağ tanınmadı. Devam etmeden önce $1 öneririz",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "ağ bilgilerini doğrula",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Toplanabilir (ERC-721) tokenlerin gönderilmesi şu anda desteklenmiyor",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "Tham gia cùng hơn 6 Triệu người dùng để cải thiện MetaMask"
},
"mismatchedChain": {
"message": "Thông tin về mạng cho mã chuỗi này không khớp với hồ sơ của chúng tôi. Bạn nên $1 trước khi tiếp tục.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "xác minh thông tin về mạng",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "Không nhận ra mạng tùy chỉnh này. Bạn nên $1 trước khi tiếp tục",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "xác minh thông tin về mạng",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Hiện không hỗ trợ gửi token sưu tập (ERC-721)",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1888,10 +1888,6 @@
"metametricsTitle": {
"message": "和600多万用户一起改进 MetaMask"
},
"mismatchedChain": {
"message": "此链 ID 的网络信息与我们的记录不符。我们建议您在继续操作之前 $1。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "验证网络信息",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3874,10 +3870,6 @@
"message": "这个自定义网络无法识别。我们建议您在继续操作之前 $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "验证网络信息",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "当前不支持发送可收藏的 (ERC-721) 代币",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -1597,10 +1597,6 @@
"metametricsTitle": {
"message": "加入 6M+ 用户来改进MetaMask"
},
"mismatchedChain": {
"message": "此链路的网络详细信息与我们的记录不匹配。我们建议您在继续操作之前$1。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "验证网络详细信息",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3157,10 +3153,6 @@
"message": "这个自定义网络无法识别。我们建议您在继续操作之前$1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "验证网络详细信息",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "当前不支持发送可收藏的 (ERC-721) 代币",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -72,11 +72,5 @@
"*://*.eth/",
"notifications"
],
"short_name": "__MSG_appName__",
"web_accessible_resources": [
{
"resources": ["inpage.js", "phishing.html"],
"matches": ["http://*/*", "https://*/*"]
}
]
"short_name": "__MSG_appName__"
}

@ -1,42 +1,89 @@
// This file is used only for manifest version 3
// Represents if importAllScripts has been run
// eslint-disable-next-line
let scriptsLoaded = false;
// Variable testMode is set to true when preparing test build.
// This helps in changing service worker execution in test environment.
const testMode = false;
const loadTimeLogs = [];
// eslint-disable-next-line import/unambiguous
function tryImport(...fileNames) {
try {
const startTime = new Date().getTime();
// eslint-disable-next-line
importScripts(...fileNames);
const endTime = new Date().getTime();
loadTimeLogs.push({
name: fileNames[0],
value: endTime - startTime,
children: [],
startTime,
endTime,
});
return true;
} catch (e) {
console.error(e);
return false;
}
return false;
}
function importAllScripts() {
// Bail if we've already imported scripts
if (scriptsLoaded) {
return;
}
const files = [];
// In testMode individual files are imported, this is to help capture load time stats
const loadFile = (fileName) => {
if (testMode) {
tryImport(fileName);
} else {
files.push(fileName);
}
};
const startImportScriptsTime = Date.now();
// value of applyLavaMoat below is dynamically replaced at build time with actual value
const applyLavaMoat = true;
tryImport('./globalthis.js');
tryImport('./sentry-install.js');
loadFile('./globalthis.js');
loadFile('./sentry-install.js');
if (applyLavaMoat) {
tryImport('./runtime-lavamoat.js');
tryImport('./lockdown-more.js');
tryImport('./policy-load.js');
loadFile('./runtime-lavamoat.js');
loadFile('./lockdown-more.js');
loadFile('./policy-load.js');
} else {
tryImport('./init-globals.js');
tryImport('./lockdown-install.js');
tryImport('./lockdown-run.js');
tryImport('./lockdown-more.js');
tryImport('./runtime-cjs.js');
loadFile('./init-globals.js');
loadFile('./lockdown-install.js');
loadFile('./lockdown-run.js');
loadFile('./lockdown-more.js');
loadFile('./runtime-cjs.js');
}
// Mark scripts as loaded
scriptsLoaded = true;
const fileList = [
// The list of files is injected at build time by replacing comment below with comma separated strings of file names
// https://github.com/MetaMask/metamask-extension/blob/496d9d81c3367931031edc11402552690c771acf/development/build/scripts.js#L406
/** FILE NAMES */
];
fileList.forEach((fileName) => tryImport(fileName));
fileList.forEach((fileName) => loadFile(fileName));
// Import all required resources
tryImport(...files);
const endImportScriptsTime = Date.now();
// for performance metrics/reference
console.log(
@ -44,7 +91,34 @@ function importAllScripts() {
(Date.now() - startImportScriptsTime) / 1000
}`,
);
// In testMode load time logs are output to console
if (testMode) {
console.log(
`Time for each import: ${JSON.stringify(
{
name: 'Total',
children: loadTimeLogs,
startTime: startImportScriptsTime,
endTime: endImportScriptsTime,
value: endImportScriptsTime - startImportScriptsTime,
version: 1,
},
undefined,
' ',
)}`,
);
}
}
// Placing script import call here ensures that scripts are inported each time service worker is activated.
importAllScripts();
// eslint-disable-next-line no-undef
self.addEventListener('install', importAllScripts);
/*
* Message event listener below loads script if they are no longer available.
* chrome below needs to be replaced by cross-browser object,
* but there is issue in importing webextension-polyfill into service worker.
* chrome does seems to work in at-least all chromium based browsers
*/
// eslint-disable-next-line no-undef
chrome.runtime.onMessage.addListener(importAllScripts);

@ -6,3 +6,17 @@ export const SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN =
'0xb8e671734ce5c8d7dfbbea5574fa4cf39f7a54a4';
export const SINGLE_CALL_BALANCES_ADDRESS_KOVAN =
'0xb1d3fbb2f83aecd196f474c16ca5d9cffa0d0ffc';
export const SINGLE_CALL_BALANCES_ADDRESS_GOERLI =
'0x9788C4E93f9002a7ad8e72633b11E8d1ecd51f9b';
export const SINGLE_CALL_BALANCES_ADDRESS_BSC =
'0x2352c63A83f9Fd126af8676146721Fa00924d7e4';
export const SINGLE_CALL_BALANCES_ADDRESS_OPTIMISM =
'0xB1c568e9C3E6bdaf755A60c7418C269eb11524FC';
export const SINGLE_CALL_BALANCES_ADDRESS_POLYGON =
'0x2352c63A83f9Fd126af8676146721Fa00924d7e4';
export const SINGLE_CALL_BALANCES_ADDRESS_AVALANCHE =
'0xD023D153a0DFa485130ECFdE2FAA7e612EF94818';
export const SINGLE_CALL_BALANCES_ADDRESS_FANTOM =
'0x07f697424ABe762bB808c109860c04eA488ff92B';
export const SINGLE_CALL_BALANCES_ADDRESS_ARBITRUM =
'0x151E24A486D7258dd7C33Fb67E4bB01919B7B32c';

@ -1,4 +1,3 @@
import querystring from 'querystring';
import pump from 'pump';
import { WindowPostMessageStream } from '@metamask/post-message-stream';
import ObjectMultiplex from 'obj-multiplex';
@ -358,12 +357,15 @@ function blockedDomainCheck() {
/**
* Redirects the current page to a phishing information page
*
* @param data
*/
function redirectToPhishingWarning() {
function redirectToPhishingWarning(data = {}) {
console.debug('MetaMask: Routing to Phishing Warning page.');
const { hostname, href } = window.location;
const { newIssueUrl } = data;
const baseUrl = process.env.PHISHING_WARNING_PAGE_URL;
window.location.href = `${baseUrl}#${querystring.stringify({
hostname: window.location.hostname,
href: window.location.href,
})}`;
const querystring = new URLSearchParams({ hostname, href, newIssueUrl });
window.location.href = `${baseUrl}#${querystring}`;
}

@ -6,8 +6,10 @@ import { MINUTE } from '../../../shared/constants/time';
import { MAINNET_CHAIN_ID } from '../../../shared/constants/network';
import { isTokenDetectionEnabledForNetwork } from '../../../shared/modules/network.utils';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
import { TOKEN_STANDARDS } from '../../../ui/helpers/constants/common';
import { ASSET_TYPES } from '../../../shared/constants/transaction';
import {
ASSET_TYPES,
TOKEN_STANDARDS,
} from '../../../shared/constants/transaction';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
// By default, poll every 3 minutes

@ -8,12 +8,19 @@ import {
TokenListController,
TokensController,
} from '@metamask/controllers';
import { MAINNET, ROPSTEN } from '../../../shared/constants/network';
import {
MAINNET,
MAINNET_NETWORK_ID,
ROPSTEN,
} from '../../../shared/constants/network';
import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
import DetectTokensController from './detect-tokens';
import NetworkController from './network';
import PreferencesController from './preferences';
const tokenIconsApiBaseUrl =
'https://static.metaswap.codefi.network/api/v1/tokenIcons';
describe('DetectTokensController', function () {
let tokenListController;
const sandbox = sinon.createSandbox();
@ -127,7 +134,6 @@ describe('DetectTokensController', function () {
});
tokenListController = new TokenListController({
chainId: '1',
useStaticTokenList: false,
onNetworkStateChange: sinon.spy(),
onPreferencesStateChange: sinon.spy(),
messenger: tokenListMessenger,
@ -179,7 +185,6 @@ describe('DetectTokensController', function () {
});
tokenListController = new TokenListController({
chainId: '3',
useStaticTokenList: false,
onNetworkStateChange: sinon.spy(),
onPreferencesStateChange: sinon.spy(),
messenger: tokenListMessengerRopsten,
@ -241,7 +246,7 @@ describe('DetectTokensController', function () {
),
);
await tokensController.removeAndIgnoreToken(tokenAddressToSkip);
await tokensController.ignoreTokens([tokenAddressToSkip]);
await controller.detectNewTokens();
assert.deepEqual(tokensController.state.tokens, [
@ -249,7 +254,8 @@ describe('DetectTokensController', function () {
address: toChecksumHexAddress(existingTokenAddress),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
image: undefined,
aggregators: [],
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${existingTokenAddress}.png`,
isERC721: false,
},
]);
@ -303,14 +309,16 @@ describe('DetectTokensController', function () {
decimals: existingToken.decimals,
symbol: existingToken.symbol,
isERC721: false,
image: undefined,
aggregators: [],
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${existingTokenAddress}.png`,
},
{
address: toChecksumHexAddress(tokenAddressToAdd),
decimals: tokenToAdd.decimals,
symbol: tokenToAdd.symbol,
image: undefined,
isERC721: false,
aggregators: [],
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${tokenAddressToAdd}.png`,
},
]);
});
@ -363,15 +371,17 @@ describe('DetectTokensController', function () {
address: toChecksumHexAddress(existingTokenAddress),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
image: undefined,
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${existingTokenAddress}.png`,
isERC721: false,
aggregators: [],
},
{
address: toChecksumHexAddress(tokenAddressToAdd),
decimals: tokenToAdd.decimals,
symbol: tokenToAdd.symbol,
image: undefined,
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${tokenAddressToAdd}.png`,
isERC721: false,
aggregators: [],
},
]);
});

@ -1,5 +1,6 @@
import EthJsEns from 'ethjs-ens';
import { ethers } from 'ethers';
import ensNetworkMap from 'ethereum-ens-network-map';
import { NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP } from '../../../../shared/constants/network';
export default class Ens {
static getNetworkEnsSupport(network) {
@ -7,17 +8,21 @@ export default class Ens {
}
constructor({ network, provider } = {}) {
this._ethJsEns = new EthJsEns({
network,
provider,
const networkName = NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP[network];
const ensAddress = ensNetworkMap[network];
const ethProvider = new ethers.providers.Web3Provider(provider, {
chainId: parseInt(network, 10),
name: networkName,
ensAddress,
});
this._ethProvider = ethProvider;
}
lookup(ensName) {
return this._ethJsEns.lookup(ensName);
return this._ethProvider.resolveName(ensName);
}
reverse(address) {
return this._ethJsEns.reverse(address);
return this._ethProvider.lookupAddress(address);
}
}

@ -20,7 +20,7 @@ describe('EnsController', function () {
describe('#constructor', function () {
it('should construct the controller given a provider and a network', async function () {
const ens = new EnsController({
provider: {},
provider: sinon.fake(),
getCurrentChainId,
onNetworkDidChange,
});

@ -18,9 +18,8 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
/**
* @typedef {import('../../../shared/constants/transaction').TransactionMeta} TransactionMeta

@ -20,7 +20,6 @@ import {
INFURA_BLOCKED_KEY,
TEST_NETWORK_TICKER_MAP,
} from '../../../../shared/constants/network';
import { SECOND } from '../../../../shared/constants/time';
import {
isPrefixedFormattedHexString,
isSafeChainId,
@ -31,7 +30,7 @@ import createInfuraClient from './createInfuraClient';
import createJsonRpcClient from './createJsonRpcClient';
const env = process.env.METAMASK_ENV;
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
let defaultProviderConfigOpts;
if (process.env.IN_TEST) {
@ -272,6 +271,11 @@ export default class NetworkController extends EventEmitter {
return NETWORK_TYPE_TO_ID_MAP[type]?.chainId || configChainId;
}
getCurrentRpcUrl() {
const { rpcUrl } = this.getProviderConfig();
return rpcUrl;
}
setRpcTarget(rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
assert.ok(
isPrefixedFormattedHexString(chainId),

@ -17,6 +17,7 @@ import {
TRANSACTION_ENVELOPE_TYPES,
TRANSACTION_EVENTS,
ASSET_TYPES,
TOKEN_STANDARDS,
} from '../../../../shared/constants/transaction';
import { SECOND } from '../../../../shared/constants/time';
@ -26,7 +27,6 @@ import {
} from '../../../../shared/constants/gas';
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import { TOKEN_STANDARDS } from '../../../../ui/helpers/constants/common';
import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
import TransactionController from '.';

@ -19,6 +19,13 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
KOVAN_CHAIN_ID,
GOERLI_CHAIN_ID,
BSC_CHAIN_ID,
OPTIMISM_CHAIN_ID,
POLYGON_CHAIN_ID,
AVALANCHE_CHAIN_ID,
FANTOM_CHAIN_ID,
ARBITRUM_CHAIN_ID,
} from '../../../shared/constants/network';
import {
@ -26,6 +33,13 @@ import {
SINGLE_CALL_BALANCES_ADDRESS_RINKEBY,
SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN,
SINGLE_CALL_BALANCES_ADDRESS_KOVAN,
SINGLE_CALL_BALANCES_ADDRESS_GOERLI,
SINGLE_CALL_BALANCES_ADDRESS_BSC,
SINGLE_CALL_BALANCES_ADDRESS_OPTIMISM,
SINGLE_CALL_BALANCES_ADDRESS_POLYGON,
SINGLE_CALL_BALANCES_ADDRESS_AVALANCHE,
SINGLE_CALL_BALANCES_ADDRESS_FANTOM,
SINGLE_CALL_BALANCES_ADDRESS_ARBITRUM,
} from '../constants/contracts';
import { bnToHex } from './util';
@ -230,6 +244,55 @@ export default class AccountTracker {
);
break;
case GOERLI_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_GOERLI,
);
break;
case BSC_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_BSC,
);
break;
case OPTIMISM_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_OPTIMISM,
);
break;
case POLYGON_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_POLYGON,
);
break;
case AVALANCHE_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_AVALANCHE,
);
break;
case FANTOM_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_FANTOM,
);
break;
case ARBITRUM_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_ARBITRUM,
);
break;
default:
await Promise.all(addresses.map(this._updateAccount.bind(this)));
}
@ -243,8 +306,17 @@ export default class AccountTracker {
* @returns {Promise} after the account balance is updated
*/
async _updateAccount(address) {
let balance = '0x0';
// query balance
const balance = await this._query.getBalance(address);
try {
balance = await this._query.getBalance(address);
} catch (error) {
if (error.data.request.method !== 'eth_getBalance') {
throw error;
}
}
const result = { address, balance };
// update accounts state
const { accounts } = this.store.getState();

@ -9,7 +9,6 @@ import {
ROPSTEN_CHAIN_ID,
BUYABLE_CHAINS_MAP,
} from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import {
TRANSAK_API_KEY,
@ -17,7 +16,7 @@ import {
COINBASEPAY_API_KEY,
} from '../constants/on-ramp';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
/**
* Create a Wyre purchase URL.

@ -1,19 +1,91 @@
import { MESSAGE_TYPE, ORIGIN_METAMASK } from '../../../shared/constants/app';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
import { SECOND } from '../../../shared/constants/time';
const USER_PROMPTED_EVENT_NAME_MAP = {
eth_signTypedData_v4: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_signTypedData_v3: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_signTypedData: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_personal_sign: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_sign: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_getEncryptionPublicKey: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED,
eth_decrypt: EVENT_NAMES.DECRYPTION_REQUESTED,
wallet_requestPermissions: EVENT_NAMES.PERMISSIONS_REQUESTED,
eth_requestAccounts: EVENT_NAMES.PERMISSIONS_REQUESTED,
/**
* These types determine how the method tracking middleware handles incoming
* requests based on the method name. There are three options right now but
* the types could be expanded to cover other options in the future.
*/
const RATE_LIMIT_TYPES = {
RATE_LIMITED: 'rate_limited',
BLOCKED: 'blocked',
NON_RATE_LIMITED: 'non_rate_limited',
};
const samplingTimeouts = {};
/**
* This object maps a method name to a RATE_LIMIT_TYPE. If not in this map the
* default is 'RATE_LIMITED'
*/
const RATE_LIMIT_MAP = {
[MESSAGE_TYPE.ETH_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.PERSONAL_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_DECRYPT]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]:
RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: RATE_LIMIT_TYPES.RATE_LIMITED,
[MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: RATE_LIMIT_TYPES.RATE_LIMITED,
[MESSAGE_TYPE.SEND_METADATA]: RATE_LIMIT_TYPES.BLOCKED,
[MESSAGE_TYPE.GET_PROVIDER_STATE]: RATE_LIMIT_TYPES.BLOCKED,
};
/**
* For events with user interaction (approve / reject | cancel) this map will
* return an object with APPROVED, REJECTED and REQUESTED keys that map to the
* appropriate event names.
*/
const EVENT_NAME_MAP = {
[MESSAGE_TYPE.ETH_SIGN]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.PERSONAL_SIGN]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_DECRYPT]: {
APPROVED: EVENT_NAMES.DECRYPTION_APPROVED,
REJECTED: EVENT_NAMES.DECRYPTION_REJECTED,
REQUESTED: EVENT_NAMES.DECRYPTION_REQUESTED,
},
[MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]: {
APPROVED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_APPROVED,
REJECTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REJECTED,
REQUESTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED,
},
[MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: {
APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED,
REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED,
REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED,
},
[MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: {
APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED,
REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED,
REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED,
},
};
const rateLimitTimeouts = {};
/**
* Returns a middleware that tracks inpage_provider usage using sampling for
@ -21,65 +93,113 @@ const samplingTimeouts = {};
* signature requests
*
* @param {object} opts - options for the rpc method tracking middleware
* @param {Function} opts.trackEvent - trackEvent method from MetaMetricsController
* @param {Function} opts.getMetricsState - get the state of MetaMetricsController
* @param {Function} opts.trackEvent - trackEvent method from
* MetaMetricsController
* @param {Function} opts.getMetricsState - get the state of
* MetaMetricsController
* @param {number} [opts.rateLimitSeconds] - number of seconds to wait before
* allowing another set of events to be tracked.
* @returns {Function}
*/
export default function createRPCMethodTrackingMiddleware({
trackEvent,
getMetricsState,
rateLimitSeconds = 60,
}) {
return function rpcMethodTrackingMiddleware(
/** @type {any} */ req,
/** @type {any} */ res,
/** @type {Function} */ next,
) {
const startTime = Date.now();
const { origin } = req;
const { origin, method } = req;
// Determine what type of rate limit to apply based on method
const rateLimitType =
RATE_LIMIT_MAP[method] ?? RATE_LIMIT_TYPES.RATE_LIMITED;
// If the rateLimitType is RATE_LIMITED check the rateLimitTimeouts
const rateLimited =
rateLimitType === RATE_LIMIT_TYPES.RATE_LIMITED &&
typeof rateLimitTimeouts[method] !== 'undefined';
// Get the participateInMetaMetrics state to determine if we should track
// anything. This is extra redundancy because this value is checked in
// the metametrics controller's trackEvent method as well.
const userParticipatingInMetaMetrics =
getMetricsState().participateInMetaMetrics === true;
// Get the event type, each of which has APPROVED, REJECTED and REQUESTED
// keys for the various events in the flow.
const eventType = EVENT_NAME_MAP[method];
// Boolean variable that reduces code duplication and increases legibility
const shouldTrackEvent =
// Don't track if the request came from our own UI or background
origin !== ORIGIN_METAMASK &&
// Don't track if this is a blocked method
rateLimitType !== RATE_LIMIT_TYPES.BLOCKED &&
// Don't track if the rate limit has been hit
rateLimited === false &&
// Don't track if the user isn't participating in metametrics
userParticipatingInMetaMetrics === true;
if (shouldTrackEvent) {
// We track an initial "requested" event as soon as the dapp calls the
// provider method. For the events not special cased this is the only
// event that will be fired and the event name will be
// 'Provider Method Called'.
const event = eventType
? eventType.REQUESTED
: EVENT_NAMES.PROVIDER_METHOD_CALLED;
const properties = {};
if (event === EVENT_NAMES.SIGNATURE_REQUESTED) {
properties.signature_type = method;
} else {
properties.method = method;
}
trackEvent({
event,
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties,
});
rateLimitTimeouts[method] = setTimeout(() => {
delete rateLimitTimeouts[method];
}, SECOND * rateLimitSeconds);
}
next((callback) => {
const endTime = Date.now();
if (!getMetricsState().participateInMetaMetrics) {
if (shouldTrackEvent === false || typeof eventType === 'undefined') {
return callback();
}
if (USER_PROMPTED_EVENT_NAME_MAP[req.method]) {
const userRejected = res.error?.code === 4001;
trackEvent({
event: USER_PROMPTED_EVENT_NAME_MAP[req.method],
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties: {
method: req.method,
status: userRejected ? 'rejected' : 'approved',
error_code: res.error?.code,
error_message: res.error?.message,
has_result: typeof res.result !== 'undefined',
duration: endTime - startTime,
},
});
} else if (typeof samplingTimeouts[req.method] === 'undefined') {
trackEvent({
event: 'Provider Method Called',
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties: {
method: req.method,
error_code: res.error?.code,
error_message: res.error?.message,
has_result: typeof res.result !== 'undefined',
duration: endTime - startTime,
},
});
// Only record one call to this method every ten seconds to avoid
// overloading network requests.
samplingTimeouts[req.method] = setTimeout(() => {
delete samplingTimeouts[req.method];
}, SECOND * 10);
// An error code of 4001 means the user rejected the request, which we
// can use here to determine which event to track.
const event =
res.error?.code === 4001 ? eventType.REJECTED : eventType.APPROVED;
const properties = {};
if (eventType.REQUESTED === EVENT_NAMES.SIGNATURE_REQUESTED) {
properties.signature_type = method;
} else {
properties.method = method;
}
trackEvent({
event,
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties,
});
return callback();
});
};

@ -0,0 +1,217 @@
import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { EVENT_NAMES } from '../../../shared/constants/metametrics';
import { SECOND } from '../../../shared/constants/time';
import createRPCMethodTrackingMiddleware from './createRPCMethodTrackingMiddleware';
const trackEvent = jest.fn();
const metricsState = { participateInMetaMetrics: null };
const getMetricsState = () => metricsState;
const handler = createRPCMethodTrackingMiddleware({
trackEvent,
getMetricsState,
rateLimitSeconds: 1,
});
function getNext(timeout = 500) {
let deferred;
const promise = new Promise((resolve) => {
deferred = {
resolve,
};
});
const cb = () => deferred.resolve();
let triggerNext;
setTimeout(() => {
deferred.resolve();
}, timeout);
return {
executeMiddlewareStack: async () => {
if (triggerNext) {
triggerNext(() => cb());
}
return await deferred.resolve();
},
promise,
next: (postReqHandler) => {
triggerNext = postReqHandler;
},
};
}
const waitForSeconds = async (seconds) =>
await new Promise((resolve) => setTimeout(resolve, SECOND * seconds));
describe('createRPCMethodTrackingMiddleware', () => {
afterEach(() => {
jest.resetAllMocks();
metricsState.participateInMetaMetrics = null;
});
describe('before participateInMetaMetrics is set', () => {
it('should not track an event for a signature request', async () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { executeMiddlewareStack, next } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).not.toHaveBeenCalled();
});
});
describe('participateInMetaMetrics is set to false', () => {
beforeEach(() => {
metricsState.participateInMetaMetrics = false;
});
it('should not track an event for a signature request', async () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { executeMiddlewareStack, next } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).not.toHaveBeenCalled();
});
});
describe('participateInMetaMetrics is set to true', () => {
beforeEach(() => {
metricsState.participateInMetaMetrics = true;
});
it(`should immediately track a ${EVENT_NAMES.SIGNATURE_REQUESTED} event`, () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { next } = getNext();
handler(req, res, next);
expect(trackEvent).toHaveBeenCalledTimes(1);
expect(trackEvent.mock.calls[0][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.SIGNATURE_REQUESTED,
properties: { signature_type: MESSAGE_TYPE.ETH_SIGN },
referrer: { url: 'some.dapp' },
});
});
it(`should track a ${EVENT_NAMES.SIGNATURE_APPROVED} event if the user approves`, async () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[1][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.SIGNATURE_APPROVED,
properties: { signature_type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4 },
referrer: { url: 'some.dapp' },
});
});
it(`should track a ${EVENT_NAMES.SIGNATURE_REJECTED} event if the user approves`, async () => {
const req = {
method: MESSAGE_TYPE.PERSONAL_SIGN,
origin: 'some.dapp',
};
const res = {
error: { code: 4001 },
};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[1][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.SIGNATURE_REJECTED,
properties: { signature_type: MESSAGE_TYPE.PERSONAL_SIGN },
referrer: { url: 'some.dapp' },
});
});
it(`should track a ${EVENT_NAMES.PERMISSIONS_APPROVED} event if the user approves`, async () => {
const req = {
method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS,
origin: 'some.dapp',
};
const res = {};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[1][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.PERMISSIONS_APPROVED,
properties: { method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS },
referrer: { url: 'some.dapp' },
});
});
it(`should never track blocked methods such as ${MESSAGE_TYPE.GET_PROVIDER_STATE}`, () => {
const req = {
method: MESSAGE_TYPE.GET_PROVIDER_STATE,
origin: 'www.notadapp.com',
};
const res = {
error: null,
};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
expect(trackEvent).not.toHaveBeenCalled();
executeMiddlewareStack();
});
it(`should only track events when not rate limited`, async () => {
const req = {
method: 'eth_chainId',
origin: 'some.dapp',
};
const res = {
error: null,
};
let callCount = 0;
while (callCount < 3) {
callCount += 1;
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
if (callCount !== 3) {
await waitForSeconds(0.6);
}
}
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[0][0].properties.method).toBe('eth_chainId');
expect(trackEvent.mock.calls[1][0].properties.method).toBe('eth_chainId');
});
});
});

@ -2,11 +2,10 @@ import base32Encode from 'base32-encode';
import base64 from 'base64-js';
import browser from 'webextension-polyfill';
import { SECOND } from '../../../../shared/constants/time';
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout';
import resolveEnsToIpfsContentId from './resolver';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
const supportedTopLevelDomains = ['eth'];

@ -1,8 +1,7 @@
import log from 'loglevel';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
const FIXTURE_SERVER_HOST = 'localhost';
const FIXTURE_SERVER_PORT = 12345;

@ -1,7 +1,10 @@
import { ethErrors, errorCodes } from 'eth-rpc-errors';
import validUrl from 'valid-url';
import { omit } from 'lodash';
import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
import {
MESSAGE_TYPE,
UNKNOWN_TICKER_SYMBOL,
} from '../../../../../shared/constants/app';
import { EVENT } from '../../../../../shared/constants/metametrics';
import {
isPrefixedFormattedHexString,
@ -16,6 +19,7 @@ const addEthereumChain = {
hookNames: {
addCustomRpc: true,
getCurrentChainId: true,
getCurrentRpcUrl: true,
findCustomRpcBy: true,
updateRpcTarget: true,
requestUserApproval: true,
@ -32,6 +36,7 @@ async function addEthereumChainHandler(
{
addCustomRpc,
getCurrentChainId,
getCurrentRpcUrl,
findCustomRpcBy,
updateRpcTarget,
requestUserApproval,
@ -145,15 +150,21 @@ async function addEthereumChainHandler(
const existingNetwork = findCustomRpcBy({ chainId: _chainId });
if (existingNetwork) {
// if the request is to add a network that is already added and configured
// with the same RPC gateway we shouldn't try to add it again.
if (existingNetwork && existingNetwork.rpcUrl === firstValidRPCUrl) {
// If the network already exists, the request is considered successful
res.result = null;
const currentChainId = getCurrentChainId();
if (currentChainId === _chainId) {
const currentRpcUrl = getCurrentRpcUrl();
// If the current chainId and rpcUrl matches that of the incoming request
// We don't need to proceed further.
if (currentChainId === _chainId && currentRpcUrl === firstValidRPCUrl) {
return end();
}
// If this network is already added with but is not the currently selected network
// Ask the user to switch the network
try {
await updateRpcTarget(
@ -236,15 +247,32 @@ async function addEthereumChainHandler(
);
}
}
const ticker = nativeCurrency?.symbol || 'ETH';
if (typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6) {
const ticker = nativeCurrency?.symbol || UNKNOWN_TICKER_SYMBOL;
if (
ticker !== UNKNOWN_TICKER_SYMBOL &&
(typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6)
) {
return end(
ethErrors.rpc.invalidParams({
message: `Expected 2-6 character string 'nativeCurrency.symbol'. Received:\n${ticker}`,
}),
);
}
// if the chainId is the same as an existing network but the ticker is different we want to block this action
// as it is potentially malicious and confusing
if (
existingNetwork &&
existingNetwork.chainId === _chainId &&
existingNetwork.ticker !== ticker
) {
return end(
ethErrors.rpc.invalidParams({
message: `nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId. Received:\n${ticker}`,
}),
);
}
try {
await addCustomRpc(
@ -261,25 +289,34 @@ async function addEthereumChainHandler(
}),
);
let rpcUrlOrigin;
try {
rpcUrlOrigin = new URL(firstValidRPCUrl).origin;
} catch {
// ignore
}
sendMetrics({
event: 'Custom Network Added',
category: EVENT.CATEGORIES.NETWORK,
referrer: {
url: origin,
},
sensitiveProperties: {
properties: {
chain_id: _chainId,
rpc_url: firstValidRPCUrl,
network_name: _chainName,
// Including network to override the default network
// property included in all events. For RPC type networks
// the MetaMetrics controller uses the rpcUrl for the network
// property.
network: firstValidRPCUrl,
network: rpcUrlOrigin,
symbol: ticker,
block_explorer_url: firstValidBlockExplorerUrl,
source: EVENT.SOURCE.TRANSACTION.DAPP,
},
sensitiveProperties: {
rpc_url: rpcUrlOrigin,
},
});
// Once the network has been added, the requested is considered successful

@ -51,12 +51,15 @@ import {
SnapController,
IframeExecutionService,
} from '@metamask/snap-controllers';
import { satisfies as satisfiesSemver } from 'semver';
///: END:ONLY_INCLUDE_IN
import {
ASSET_TYPES,
TRANSACTION_STATUSES,
TRANSACTION_TYPES,
} from '../../shared/constants/transaction';
import { PHISHING_NEW_ISSUE_URLS } from '../../shared/constants/phishing';
import {
GAS_API_BASE_URL,
GAS_DEV_API_BASE_URL,
@ -85,7 +88,7 @@ import {
POLLING_TOKEN_ENVIRONMENT_TYPES,
SUBJECT_TYPES,
} from '../../shared/constants/app';
import { EVENT } from '../../shared/constants/metametrics';
import { EVENT, EVENT_NAMES } from '../../shared/constants/metametrics';
import { hexToDecimal } from '../../ui/helpers/utils/conversions.util';
import { getTokenValueParam } from '../../ui/helpers/utils/token-util';
@ -245,35 +248,28 @@ export default class MetamaskController extends EventEmitter {
config: { provider: this.provider },
state: initState.TokensController,
});
process.env.TOKEN_DETECTION_V2
? (this.assetsContractController = new AssetsContractController({
onPreferencesStateChange: (listener) =>
this.preferencesController.store.subscribe(listener),
onNetworkStateChange: (cb) =>
this.networkController.store.subscribe((networkState) => {
const modifiedNetworkState = {
...networkState,
provider: {
...networkState.provider,
chainId: hexToDecimal(networkState.provider.chainId),
},
};
return cb(modifiedNetworkState);
}),
config: {
provider: this.provider,
},
state: initState.AssetsContractController,
}))
: (this.assetsContractController = new AssetsContractController(
{
onPreferencesStateChange: (listener) =>
this.preferencesController.store.subscribe(listener),
},
{
provider: this.provider,
},
));
this.assetsContractController = new AssetsContractController(
{
onPreferencesStateChange: (listener) =>
this.preferencesController.store.subscribe(listener),
onNetworkStateChange: (cb) =>
this.networkController.store.subscribe((networkState) => {
const modifiedNetworkState = {
...networkState,
provider: {
...networkState.provider,
chainId: hexToDecimal(networkState.provider.chainId),
},
};
return cb(modifiedNetworkState);
}),
},
{
provider: this.provider,
},
initState.AssetsContractController,
);
this.collectiblesController = new CollectiblesController(
{
@ -301,6 +297,21 @@ export default class MetamaskController extends EventEmitter {
getERC1155TokenURI: this.assetsContractController.getERC1155TokenURI.bind(
this.assetsContractController,
),
onCollectibleAdded: ({ address, symbol, tokenId, standard, source }) =>
this.metaMetricsController.trackEvent({
event: EVENT_NAMES.NFT_ADDED,
category: EVENT.CATEGORIES.WALLET,
properties: {
token_contract_address: address,
token_symbol: symbol,
asset_type: ASSET_TYPES.COLLECTIBLE,
token_standard: standard,
source,
},
sensitiveProperties: {
tokenId,
},
}),
},
{},
initState.CollectiblesController,
@ -417,50 +428,23 @@ export default class MetamaskController extends EventEmitter {
const tokenListMessenger = this.controllerMessenger.getRestricted({
name: 'TokenListController',
});
process.env.TOKEN_DETECTION_V2
? (this.tokenListController = new TokenListController({
chainId: hexToDecimal(this.networkController.getCurrentChainId()),
onNetworkStateChange: (cb) =>
this.networkController.store.subscribe((networkState) => {
const modifiedNetworkState = {
...networkState,
provider: {
...networkState.provider,
chainId: hexToDecimal(networkState.provider.chainId),
},
};
return cb(modifiedNetworkState);
}),
messenger: tokenListMessenger,
state: initState.TokenListController,
}))
: (this.tokenListController = new TokenListController({
chainId: hexToDecimal(this.networkController.getCurrentChainId()),
useStaticTokenList: !this.preferencesController.store.getState()
.useTokenDetection,
onNetworkStateChange: (cb) =>
this.networkController.store.subscribe((networkState) => {
const modifiedNetworkState = {
...networkState,
provider: {
...networkState.provider,
chainId: hexToDecimal(networkState.provider.chainId),
},
};
return cb(modifiedNetworkState);
}),
onPreferencesStateChange: (cb) =>
this.preferencesController.store.subscribe((preferencesState) => {
const modifiedPreferencesState = {
...preferencesState,
useStaticTokenList: !this.preferencesController.store.getState()
.useTokenDetection,
};
return cb(modifiedPreferencesState);
}),
messenger: tokenListMessenger,
state: initState.TokenListController,
}));
this.tokenListController = new TokenListController({
chainId: hexToDecimal(this.networkController.getCurrentChainId()),
onNetworkStateChange: (cb) =>
this.networkController.store.subscribe((networkState) => {
const modifiedNetworkState = {
...networkState,
provider: {
...networkState.provider,
chainId: hexToDecimal(networkState.provider.chainId),
},
};
return cb(modifiedNetworkState);
}),
messenger: tokenListMessenger,
state: initState.TokenListController,
});
this.phishingController = new PhishingController();
@ -642,7 +626,7 @@ export default class MetamaskController extends EventEmitter {
///: BEGIN:ONLY_INCLUDE_IN(flask)
this.snapExecutionService = new IframeExecutionService({
iframeUrl: new URL(
'https://metamask.github.io/iframe-execution-environment/0.5.0',
'https://metamask.github.io/iframe-execution-environment/0.5.2',
),
messenger: this.controllerMessenger.getRestricted({
name: 'ExecutionService',
@ -654,7 +638,8 @@ export default class MetamaskController extends EventEmitter {
name: 'SnapController',
allowedEvents: [
'ExecutionService:unhandledError',
'ExecutionService:unresponsive',
'ExecutionService:outboundRequest',
'ExecutionService:outboundResponse',
],
allowedActions: [
`${this.permissionController.name}:getEndowments`,
@ -664,29 +649,51 @@ export default class MetamaskController extends EventEmitter {
`${this.permissionController.name}:requestPermissions`,
`${this.permissionController.name}:revokeAllPermissions`,
`${this.permissionController.name}:revokePermissionForAllSubjects`,
'ExecutionService:executeSnap',
'ExecutionService:getRpcRequestHandler',
'ExecutionService:terminateSnap',
'ExecutionService:terminateAllSnaps',
],
});
const SNAP_BLOCKLIST = [
{
id: 'npm:@consensys/starknet-snap',
versionRange: '<0.1.11',
},
];
this.snapController = new SnapController({
environmentEndowmentPermissions: Object.values(EndowmentPermissions),
terminateAllSnaps: this.snapExecutionService.terminateAllSnaps.bind(
this.snapExecutionService,
),
terminateSnap: this.snapExecutionService.terminateSnap.bind(
this.snapExecutionService,
),
executeSnap: this.snapExecutionService.executeSnap.bind(
this.snapExecutionService,
),
getRpcMessageHandler: this.snapExecutionService.getRpcMessageHandler.bind(
this.snapExecutionService,
),
closeAllConnections: this.removeAllConnections.bind(this),
// Prefix subject with appKeyType to generate separate keys for separate uses
getAppKey: async (subject, appKeyType) => {
await this.appStateController.getUnlockPromise(true);
return this.getAppKeyForSubject(`${appKeyType}:${subject}`);
},
checkBlockList: async (snapsToCheck) => {
return Object.entries(snapsToCheck).reduce(
(acc, [snapId, snapVersion]) => {
const blockInfo = SNAP_BLOCKLIST.find(
(blocked) =>
blocked.id === snapId &&
satisfiesSemver(snapVersion, blocked.versionRange, {
includePrerelease: true,
}),
);
const cur = blockInfo
? {
blocked: true,
reason: blockInfo.reason,
infoUrl: blockInfo.infoUrl,
}
: { blocked: false };
return { ...acc, [snapId]: cur };
},
{},
);
},
state: initState.SnapController,
messenger: snapControllerMessenger,
});
@ -1129,9 +1136,9 @@ export default class MetamaskController extends EventEmitter {
this.controllerMessenger,
'SnapController:get',
),
getSnapRpcHandler: this.controllerMessenger.call.bind(
handleSnapRpcRequest: this.controllerMessenger.call.bind(
this.controllerMessenger,
'SnapController:getRpcMessageHandler',
'SnapController:handleRpcRequest',
),
getSnapState: this.controllerMessenger.call.bind(
this.controllerMessenger,
@ -1255,7 +1262,7 @@ export default class MetamaskController extends EventEmitter {
// Record Snap metadata whenever a Snap is added to state.
this.controllerMessenger.subscribe(
`${this.snapController.name}:snapAdded`,
(snapId, snap, svgIcon = null) => {
(snap, svgIcon = null) => {
const {
manifest: { proposedName },
version,
@ -1263,7 +1270,7 @@ export default class MetamaskController extends EventEmitter {
this.subjectMetadataController.addSubjectMetadata({
subjectType: SUBJECT_TYPES.SNAP,
name: proposedName,
origin: snapId,
origin: snap.id,
version,
svgIcon,
});
@ -1272,12 +1279,28 @@ export default class MetamaskController extends EventEmitter {
this.controllerMessenger.subscribe(
`${this.snapController.name}:snapInstalled`,
(snapId) => {
(truncatedSnap) => {
this.metaMetricsController.trackEvent({
event: 'Snap Installed',
category: EVENT.CATEGORIES.SNAPS,
properties: {
snap_id: snapId,
snap_id: truncatedSnap.id,
version: truncatedSnap.version,
},
});
},
);
this.controllerMessenger.subscribe(
`${this.snapController.name}:snapUpdated`,
(newSnap, oldVersion) => {
this.metaMetricsController.trackEvent({
event: 'Snap Updated',
category: EVENT.CATEGORIES.SNAPS,
properties: {
snap_id: newSnap.id,
old_version: oldVersion,
new_version: newSnap.version,
},
});
},
@ -1285,12 +1308,12 @@ export default class MetamaskController extends EventEmitter {
this.controllerMessenger.subscribe(
`${this.snapController.name}:snapTerminated`,
(snapId) => {
(truncatedSnap) => {
const approvals = Object.values(
this.approvalController.state.pendingApprovals,
).filter(
(approval) =>
approval.origin === snapId &&
approval.origin === truncatedSnap.id &&
approval.type === MESSAGE_TYPE.SNAP_CONFIRM,
);
for (const approval of approvals) {
@ -1586,7 +1609,6 @@ export default class MetamaskController extends EventEmitter {
tokensController,
),
updateTokenType: tokensController.updateTokenType.bind(tokensController),
removeToken: tokensController.removeAndIgnoreToken.bind(tokensController),
setAccountLabel: preferencesController.setAccountLabel.bind(
preferencesController,
),
@ -1960,20 +1982,14 @@ export default class MetamaskController extends EventEmitter {
: null,
/** Token Detection V2 */
addDetectedTokens: process.env.TOKEN_DETECTION_V2
? tokensController.addDetectedTokens.bind(tokensController)
: null,
importTokens: process.env.TOKEN_DETECTION_V2
? tokensController.importTokens.bind(tokensController)
: null,
ignoreTokens: process.env.TOKEN_DETECTION_V2
? tokensController.ignoreTokens.bind(tokensController)
: null,
getBalancesInSingleCall: process.env.TOKEN_DETECTION_V2
? assetsContractController.getBalancesInSingleCall.bind(
assetsContractController,
)
: null,
addDetectedTokens: tokensController.addDetectedTokens.bind(
tokensController,
),
addImportedTokens: tokensController.addTokens.bind(tokensController),
ignoreTokens: tokensController.ignoreTokens.bind(tokensController),
getBalancesInSingleCall: assetsContractController.getBalancesInSingleCall.bind(
assetsContractController,
),
};
}
@ -2064,6 +2080,31 @@ export default class MetamaskController extends EventEmitter {
blockExplorerUrl,
},
);
let rpcUrlOrigin;
try {
rpcUrlOrigin = new URL(rpcUrl).origin;
} catch {
// ignore
}
this.metaMetricsController.trackEvent({
event: 'Custom Network Added',
category: EVENT.CATEGORIES.NETWORK,
referrer: {
url: rpcUrlOrigin,
},
properties: {
chain_id: chainId,
network_name: chainName,
network: rpcUrlOrigin,
symbol: ticker,
block_explorer_url: blockExplorerUrl,
source: EVENT.SOURCE.NETWORK.POPULAR_NETWORK_LIST,
},
sensitiveProperties: {
rpc_url: rpcUrlOrigin,
},
});
}
/**
@ -3317,9 +3358,13 @@ export default class MetamaskController extends EventEmitter {
if (sender.url) {
const { hostname } = new URL(sender.url);
// Check if new connection is blocked if phishing detection is on
if (usePhishDetect && this.phishingController.test(hostname)) {
log.debug('MetaMask - sending phishing warning for', hostname);
this.sendPhishingWarning(connectionStream, hostname);
const phishingTestResponse = this.phishingController.test(hostname);
if (usePhishDetect && phishingTestResponse?.result) {
this.sendPhishingWarning(
connectionStream,
hostname,
phishingTestResponse,
);
return;
}
}
@ -3397,11 +3442,15 @@ export default class MetamaskController extends EventEmitter {
* @param {*} connectionStream - The duplex stream to the per-page script,
* for sending the reload attempt to.
* @param {string} hostname - The hostname that triggered the suspicion.
* @param {object} phishingTestResponse - Result of calling `phishingController.test`,
* which is the result of calling eth-phishing-detects detector.check method https://github.com/MetaMask/eth-phishing-detect/blob/master/src/detector.js#L55-L112
*/
sendPhishingWarning(connectionStream, hostname) {
sendPhishingWarning(connectionStream, hostname, phishingTestResponse) {
const newIssueUrl = PHISHING_NEW_ISSUE_URLS[phishingTestResponse?.name];
const mux = setupMultiplex(connectionStream);
const phishingStream = mux.createStream('phishing');
phishingStream.write({ hostname });
phishingStream.write({ hostname, newIssueUrl });
}
/**
@ -3642,6 +3691,9 @@ export default class MetamaskController extends EventEmitter {
getCurrentChainId: this.networkController.getCurrentChainId.bind(
this.networkController,
),
getCurrentRpcUrl: this.networkController.getCurrentRpcUrl.bind(
this.networkController,
),
setProviderType: this.networkController.setProviderType.bind(
this.networkController,
),

@ -49,7 +49,10 @@ function createZipTask(platform, buildType, version) {
gulp.src(`dist/${platform}/**`),
// sort files and set `mtime` to epoch to ensure zip build is deterministic
sort(),
gulpZip(`${path}.zip`, { modifiedTime: new Date(0) }),
// Modified time set to an arbitrary static date to ensure build the is reproducible.
// The date chosen is MetaMask's birthday. Originally we chose the Unix epoch, but this
// resulted in invalid dates on certain timezones/operating systems.
gulpZip(`${path}.zip`, { modifiedTime: new Date('2016-07-14T00:00:00') }),
gulp.dest('builds'),
);
};

@ -36,7 +36,6 @@ const metamaskrc = require('rc')('metamask', {
COLLECTIBLES_V1: process.env.COLLECTIBLES_V1,
PHISHING_WARNING_PAGE_URL: process.env.PHISHING_WARNING_PAGE_URL,
TOKEN_DETECTION_V2: process.env.TOKEN_DETECTION_V2,
ADD_POPULAR_NETWORKS: process.env.ADD_POPULAR_NETWORKS,
SEGMENT_HOST: process.env.SEGMENT_HOST,
SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY,
SEGMENT_BETA_WRITE_KEY: process.env.SEGMENT_BETA_WRITE_KEY,
@ -197,22 +196,22 @@ function createScriptTasks({
// internal tasks
const core = {
// dev tasks (live reload)
dev: createTasksForBuildJsExtension({
dev: createTasksForScriptBundles({
taskPrefix: 'scripts:core:dev',
devMode: true,
}),
testDev: createTasksForBuildJsExtension({
testDev: createTasksForScriptBundles({
taskPrefix: 'scripts:core:test-live',
devMode: true,
testing: true,
}),
// built for CI tests
test: createTasksForBuildJsExtension({
test: createTasksForScriptBundles({
taskPrefix: 'scripts:core:test',
testing: true,
}),
// production
prod: createTasksForBuildJsExtension({ taskPrefix: 'scripts:core:prod' }),
prod: createTasksForScriptBundles({ taskPrefix: 'scripts:core:prod' }),
};
// high level tasks
@ -220,7 +219,11 @@ function createScriptTasks({
const { dev, test, testDev, prod } = core;
return { dev, test, testDev, prod };
function createTasksForBuildJsExtension({ taskPrefix, devMode, testing }) {
function createTasksForScriptBundles({
taskPrefix,
devMode = false,
testing = false,
}) {
const standardEntryPoints = ['background', 'ui', 'content-script'];
const standardSubtask = createTask(
`${taskPrefix}:standardEntryPoints`,
@ -247,19 +250,19 @@ function createScriptTasks({
// because inpage bundle result is included inside contentscript
const contentscriptSubtask = createTask(
`${taskPrefix}:contentscript`,
createTaskForBundleContentscript({ devMode, testing }),
createContentscriptBundle({ devMode, testing }),
);
// this can run whenever
const disableConsoleSubtask = createTask(
`${taskPrefix}:disable-console`,
createTaskForBundleDisableConsole({ devMode, testing }),
createDisableConsoleBundle({ devMode, testing }),
);
// this can run whenever
const installSentrySubtask = createTask(
`${taskPrefix}:sentry`,
createTaskForBundleSentry({ devMode, testing }),
createSentryBundle({ devMode, testing }),
);
// task for initiating browser livereload
@ -297,7 +300,7 @@ function createScriptTasks({
return composeParallel(initiateLiveReload, ...allSubtasks);
}
function createTaskForBundleDisableConsole({ devMode, testing }) {
function createDisableConsoleBundle({ devMode, testing }) {
const label = 'disable-console';
return createNormalBundle({
browserPlatforms,
@ -314,7 +317,7 @@ function createScriptTasks({
});
}
function createTaskForBundleSentry({ devMode, testing }) {
function createSentryBundle({ devMode, testing }) {
const label = 'sentry-install';
return createNormalBundle({
browserPlatforms,
@ -332,7 +335,7 @@ function createScriptTasks({
}
// the "contentscript" bundle contains the "inpage" bundle
function createTaskForBundleContentscript({ devMode, testing }) {
function createContentscriptBundle({ devMode, testing }) {
const inpage = 'inpage';
const contentscript = 'contentscript';
return composeSeries(
@ -370,23 +373,29 @@ const postProcessServiceWorker = (
mv3BrowserPlatforms,
fileList,
applyLavaMoat,
testing,
) => {
mv3BrowserPlatforms.forEach((browser) => {
const appInitFile = `./dist/${browser}/app-init.js`;
const fileContent = readFileSync('./app/scripts/app-init.js', 'utf8');
const fileOutput = fileContent
.replace('/** FILE NAMES */', fileList)
.replace(
let fileOutput = fileContent.replace('/** FILE NAMES */', fileList);
if (testing) {
fileOutput = fileOutput.replace('testMode = false', 'testMode = true');
} else {
// Setting applyLavaMoat to true in testing mode
// This is to enable capturing initialisation time stats using e2e with lavamoat statsMode enabled
fileOutput = fileOutput.replace(
'const applyLavaMoat = true;',
`const applyLavaMoat = ${applyLavaMoat};`,
);
}
writeFileSync(appInitFile, fileOutput);
});
};
// Function generates app-init.js for browsers chrome, brave and opera.
// It dynamically injects list of files generated in the build.
async function bundleMV3AppInitialiser({
async function createManifestV3AppInitializationBundle({
jsBundles,
browserPlatforms,
buildType,
@ -396,6 +405,7 @@ async function bundleMV3AppInitialiser({
policyOnly,
shouldLintFenceFiles,
applyLavaMoat,
version,
}) {
const label = 'app-init';
// TODO: remove this filter for firefox once MV3 is supported in it
@ -418,18 +428,39 @@ async function bundleMV3AppInitialiser({
testing,
policyOnly,
shouldLintFenceFiles,
version,
})();
postProcessServiceWorker(mv3BrowserPlatforms, fileList, applyLavaMoat);
postProcessServiceWorker(
mv3BrowserPlatforms,
fileList,
applyLavaMoat,
testing,
);
let prevChromeFileContent;
watch('./dist/chrome/app-init.js', () => {
const chromeFileContent = readFileSync('./dist/chrome/app-init.js', 'utf8');
if (chromeFileContent !== prevChromeFileContent) {
prevChromeFileContent = chromeFileContent;
postProcessServiceWorker(mv3BrowserPlatforms, fileList, applyLavaMoat);
}
});
// If the application is running in development mode, we watch service worker file to
// in case the file is changes we need to process it again to replace "/** FILE NAMES */", "testMode" etc.
if (devMode && !testing) {
let prevChromeFileContent;
watch('./dist/chrome/app-init.js', () => {
const chromeFileContent = readFileSync(
'./dist/chrome/app-init.js',
'utf8',
);
if (chromeFileContent !== prevChromeFileContent) {
prevChromeFileContent = chromeFileContent;
postProcessServiceWorker(mv3BrowserPlatforms, fileList, applyLavaMoat);
}
});
}
// Code below is used to set statsMode to true when testing in MV3
// This is used to capture module initialisation stats using lavamoat.
if (testing) {
const content = readFileSync('./dist/chrome/runtime-lavamoat.js', 'utf8');
const fileOutput = content.replace('statsMode = false', 'statsMode = true');
writeFileSync('./dist/chrome/runtime-lavamoat.js', fileOutput);
}
console.log(`Bundle end: service worker app-init.js`);
}
@ -597,7 +628,7 @@ function createFactoredBuild({
...commonSet.values(),
...groupSet.values(),
].map((label) => `./${label}.js`);
await bundleMV3AppInitialiser({
await createManifestV3AppInitializationBundle({
jsBundles,
browserPlatforms,
buildType,
@ -607,6 +638,7 @@ function createFactoredBuild({
policyOnly,
shouldLintFenceFiles,
applyLavaMoat,
version,
});
}
break;
@ -630,7 +662,7 @@ function createFactoredBuild({
}
});
await bundleIt(buildConfiguration, { reloadOnChange });
await createBundle(buildConfiguration, { reloadOnChange });
};
}
@ -640,11 +672,9 @@ function createNormalBundle({
destFilepath,
devMode,
entryFilepath,
extraEntries = [],
ignoredFiles,
label,
policyOnly,
modulesToExpose,
shouldLintFenceFiles,
testing,
version,
@ -678,14 +708,7 @@ function createNormalBundle({
});
// set bundle entries
bundlerOpts.entries = [...extraEntries];
if (entryFilepath) {
bundlerOpts.entries.push(entryFilepath);
}
if (modulesToExpose) {
bundlerOpts.require = bundlerOpts.require.concat(modulesToExpose);
}
bundlerOpts.entries = [entryFilepath];
// instrument pipeline
events.on('configurePipeline', ({ pipeline }) => {
@ -701,7 +724,7 @@ function createNormalBundle({
});
});
await bundleIt(buildConfiguration, { reloadOnChange });
await createBundle(buildConfiguration, { reloadOnChange });
};
}
@ -754,7 +777,7 @@ function setupBundlerDefaults(
// Look for TypeScript files when walking the dependency tree
extensions,
// Use entryFilepath for moduleIds, easier to determine origin file
fullPaths: devMode,
fullPaths: devMode || testing,
// For sourcemaps
debug: true,
});
@ -856,7 +879,7 @@ function setupSourcemaps(buildConfiguration, { devMode }) {
});
}
async function bundleIt(buildConfiguration, { reloadOnChange }) {
async function createBundle(buildConfiguration, { reloadOnChange }) {
const { label, bundlerOpts, events } = buildConfiguration;
const bundler = browserify(bundlerOpts);
@ -941,7 +964,6 @@ function getEnvironmentVariables({ buildType, devMode, testing, version }) {
ONBOARDING_V2: metamaskrc.ONBOARDING_V2 === '1',
COLLECTIBLES_V1: metamaskrc.COLLECTIBLES_V1 === '1',
TOKEN_DETECTION_V2: metamaskrc.TOKEN_DETECTION_V2 === '1',
ADD_POPULAR_NETWORKS: metamaskrc.ADD_POPULAR_NETWORKS === '1',
};
}

@ -0,0 +1,170 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
/>
<link rel="stylesheet" type="text/css" href="../lib/d3-flamegraph.css" />
<style>
/* Space out content a bit */
body {
padding-top: 20px;
padding-bottom: 20px;
}
/* Custom page header */
.header {
padding-bottom: 20px;
padding-right: 15px;
padding-left: 15px;
border-bottom: 1px solid #e5e5e5;
}
/* Make the masthead heading the same height as the navigation */
.header h3 {
margin-top: 0;
margin-bottom: 0;
line-height: 40px;
}
/* Customize container */
.container {
max-width: 990px;
}
</style>
<title>Performance Measurements</title>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="header clearfix">
<nav>
<div class="pull-right">
<form class="form-inline" id="form">
<a class="btn" href="javascript: resetZoom();">Reset zoom</a>
<a class="btn" href="javascript: clear();">Clear</a>
<div class="form-group">
<input type="text" class="form-control" id="term" />
</div>
<a class="btn btn-primary" href="javascript: search();">Search</a>
</form>
</div>
</nav>
<h3 class="text-muted">d3-flame-graph</h3>
</div>
<div id="chart"></div>
<hr />
<div id="details"></div>
</div>
<!-- D3.js -->
<script src="https://d3js.org/d3.v7.js" charset="utf-8"></script>
<!-- d3-flamegraph -->
<script type="text/javascript" src="../lib/d3-flamegraph.js"></script>
<script
type="text/javascript"
src="../lib/d3-flamegraph-tooltip.js"
></script>
<script type="text/javascript">
var chart = flamegraph()
.width(960)
.cellHeight(18)
.transitionDuration(750)
.minFrameSize(5)
.transitionEase(d3.easeCubic)
.sort(true)
//Example to sort in reverse order
//.sort(function(a,b){ return d3.descending(a.name, b.name);})
.title('')
.onClick(onClick)
.selfValue(false)
.setColorMapper((d, originalColor) =>
d.highlight ? '#6aff8f' : originalColor,
);
// Example on how to use custom a tooltip.
var tip = flamegraph.tooltip
.defaultFlamegraphTooltip()
.text((d) => 'name: ' + d.data.name + ', value: ' + d.data.value);
chart.tooltip(tip);
var details = document.getElementById('details');
chart.setDetailsElement(details);
// Example on how to use searchById() function in flamegraph.
// To invoke this function after loading the graph itself, this function should be registered in d3 datum(data).call()
// (See d3.json invocation in this file)
function invokeFind() {
var searchId = parseInt(location.hash.substring(1), 10);
if (searchId) {
find(searchId);
}
}
// Example on how to use custom labels
// var label = function(d) {
// return "name: " + d.name + ", value: " + d.value;
// }
// chart.label(label);
// Example of how to set fixed chart height
// chart.height(540);
d3.json('stacks.json')
.then((data) => {
d3.select('#chart').datum(data).call(chart).call(invokeFind);
})
.catch((error) => {
return console.warn(error);
});
document
.getElementById('form')
.addEventListener('submit', function (event) {
event.preventDefault();
search();
});
function search() {
var term = document.getElementById('term').value;
chart.search(term);
}
function find(id) {
var elem = chart.findById(id);
if (elem) {
console.log(elem);
chart.zoomTo(elem);
}
}
function clear() {
document.getElementById('term').value = '';
chart.clear();
}
function resetZoom() {
chart.resetZoom();
}
function onClick(d) {
console.info(`Clicked on ${d.data.name}, id: "${d.id}"`);
history.pushState({ id: d.id }, d.data.name, `#${d.id}`);
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,46 @@
.d3-flame-graph rect {
stroke: #EEEEEE;
fill-opacity: .8;
}
.d3-flame-graph rect:hover {
stroke: #474747;
stroke-width: 0.5;
cursor: pointer;
}
.d3-flame-graph-label {
pointer-events: none;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 12px;
font-family: Verdana;
margin-left: 4px;
margin-right: 4px;
line-height: 1.5;
padding: 0 0 0;
font-weight: 400;
color: black;
text-align: left;
}
.d3-flame-graph .fade {
opacity: 0.6 !important;
}
.d3-flame-graph .title {
font-size: 20px;
font-family: Verdana;
}
.d3-flame-graph-tip {
background-color: black;
border: none;
border-radius: 3px;
padding: 5px 10px 5px 10px;
min-width: 250px;
text-align: left;
color: white;
z-index: 10;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,67 @@
<html>
<head>
<script type="text/javascript" src="./jquery.min.js"></script>
<style>
table {
border: 1px solid black;
border-collapse: collapse;
}
tr {
border: 1px solid black;
}
</style>
<script>
$(function () {
var loadTime = [];
$.getJSON('stats.json', function (data) {
$.each(data.children, function (index, datum) {
if (datum.name) {
var tblRow =
'<tr>' +
'<td>' +
index +
'</td>' +
'<td>' +
datum.name +
'</td>' +
'<td>' +
datum.value +
'</td>' +
'</tr>';
$(tblRow).appendTo('#loaddata tbody');
}
});
$(
'<tr>' +
'<td>' +
'Total' +
'</td>' +
'<td>' +
'--' +
'</td>' +
'<td>' +
data.value +
'</td>' +
'</tr>',
).appendTo('#loaddata tbody');
});
});
</script>
</head>
<body>
<div class="wrapper">
<div class="profile">
<table id="loaddata">
<thead>
<th>S.No</th>
<th>Name</th>
<th>TotalTime</th>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</body>
</html>

File diff suppressed because one or more lines are too long

@ -94,6 +94,14 @@ async function start() {
// links to bundle browser builds
const depVizUrl = `${BUILD_LINK_BASE}/build-artifacts/build-viz/index.html`;
const depVizLink = `<a href="${depVizUrl}">Build System</a>`;
const moduleInitStatsBackgroundUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/initialisation/background/index.html`;
const moduleInitStatsBackgroundLink = `<a href="${moduleInitStatsBackgroundUrl}">Background Module Init Stats</a>`;
const moduleInitStatsUIUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/initialisation/ui/index.html`;
const moduleInitStatsUILink = `<a href="${moduleInitStatsUIUrl}">UI Init Stats</a>`;
const moduleLoadStatsUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/load_time/index.html`;
const moduleLoadStatsLink = `<a href="${moduleLoadStatsUrl}">Module Load Stats</a>`;
const bundleSizeStatsUrl = `${BUILD_LINK_BASE}/test-artifacts/chrome/mv3/bundle_size.json`;
const bundleSizeStatsLink = `<a href="${bundleSizeStatsUrl}">Bundle Size Stats</a>`;
// link to artifacts
const allArtifactsUrl = `https://circleci.com/gh/MetaMask/metamask-extension/${CIRCLE_BUILD_NUM}#artifacts/containers/0`;
@ -103,6 +111,10 @@ async function start() {
`builds (beta): ${betaBuildLinks}`,
`builds (flask): ${flaskBuildLinks}`,
`build viz: ${depVizLink}`,
`mv3: ${moduleInitStatsBackgroundLink}`,
`mv3: ${moduleInitStatsUILink}`,
`mv3: ${moduleLoadStatsLink}`,
`mv3: ${bundleSizeStatsLink}`,
`code coverage: ${coverageLink}`,
`storybook: ${storybookLink}`,
`<a href="${allArtifactsUrl}">all artifacts</a>`,

@ -1,6 +1,7 @@
module.exports = {
collectCoverageFrom: [
'<rootDir>/app/scripts/controllers/permissions/**/*.js',
'<rootDir>/app/scripts/lib/createRPCMethodTrackingMiddleware.js',
'<rootDir>/shared/**/*.js',
'<rootDir>/ui/**/*.js',
],
@ -20,6 +21,12 @@ module.exports = {
lines: 100,
statements: 100,
},
'./app/scripts/lib/createRPCMethodTrackingMiddleware.js': {
branches: 95.65,
functions: 100,
lines: 100,
statements: 100,
},
},
// TODO: enable resetMocks
// resetMocks: true,
@ -34,6 +41,7 @@ module.exports = {
'<rootDir>/app/scripts/platforms/*.test.js',
'<rootDir>app/scripts/controllers/network/**/*.test.js',
'<rootDir>/app/scripts/controllers/permissions/**/*.test.js',
'<rootDir>/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js',
],
testTimeout: 2500,
transform: {

@ -3168,43 +3168,6 @@
"watchify>xtend": true
}
},
"@metamask/post-message-stream": {
"globals": {
"addEventListener": true,
"location.origin": true,
"onmessage": "write",
"postMessage": true,
"removeEventListener": true
},
"packages": {
"@metamask/post-message-stream>readable-stream": true
}
},
"@metamask/post-message-stream>readable-stream": {
"packages": {
"@metamask/post-message-stream>readable-stream>safe-buffer": true,
"@metamask/post-message-stream>readable-stream>string_decoder": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true,
"vinyl>cloneable-readable>process-nextick-args": true
}
},
"@metamask/post-message-stream>readable-stream>safe-buffer": {
"packages": {
"browserify>buffer": true
}
},
"@metamask/post-message-stream>readable-stream>string_decoder": {
"packages": {
"@metamask/post-message-stream>readable-stream>safe-buffer": true
}
},
"@metamask/providers>@metamask/object-multiplex": {
"globals": {
"console.warn": true
@ -3217,147 +3180,13 @@
},
"@metamask/rpc-methods": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers": true,
"@metamask/controllers": true,
"@metamask/rpc-methods>@metamask/key-tree": true,
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers": true,
"eth-rpc-errors": true
}
},
"@metamask/rpc-methods>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry": true,
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/rpc-methods>@metamask/controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
}
},
"@metamask/rpc-methods>@metamask/key-tree": {
"packages": {
"@metamask/rpc-methods>@metamask/key-tree>@noble/ed25519": true,
@ -3418,148 +3247,14 @@
"setInterval": true
},
"packages": {
"@metamask/controllers": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/smart-transactions-controller>@metamask/controllers": true,
"@metamask/smart-transactions-controller>bignumber.js": true,
"@metamask/smart-transactions-controller>fast-json-patch": true,
"ethers": true,
"lodash": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry": true,
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/smart-transactions-controller>@metamask/controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>nanoid": {
"globals": {
"crypto.getRandomValues": true
@ -3582,7 +3277,6 @@
"@metamask/snap-controllers": {
"globals": {
"URL": true,
"Worker": true,
"clearTimeout": true,
"console.error": true,
"console.info": true,
@ -3595,13 +3289,13 @@
"setTimeout": true
},
"packages": {
"@metamask/post-message-stream": true,
"@metamask/controllers": true,
"@metamask/providers>@metamask/object-multiplex": true,
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers>@metamask/browser-passworder": true,
"@metamask/snap-controllers>@metamask/controllers": true,
"@metamask/snap-controllers>@metamask/execution-environments": true,
"@metamask/snap-controllers>@metamask/obs-store": true,
"@metamask/snap-controllers>@metamask/post-message-stream": true,
"@metamask/snap-controllers>ajv": true,
"@metamask/snap-controllers>concat-stream": true,
"@metamask/snap-controllers>gunzip-maybe": true,
@ -3632,153 +3326,78 @@
"browserify>buffer": true
}
},
"@metamask/snap-controllers>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry": true,
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/snap-controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry": {
"@metamask/snap-controllers>@metamask/obs-store": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": true
"@metamask/snap-controllers>@metamask/obs-store>through2": true,
"browserify>stream-browserify": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"@metamask/snap-controllers>@metamask/obs-store>through2": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream": true,
"browserify>process": true,
"browserify>util": true,
"watchify>xtend": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>process-nextick-args": true,
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>string_decoder": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>process-nextick-args": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
"browserify>process": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>string_decoder": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"@metamask/snap-controllers>@metamask/post-message-stream": {
"globals": {
"console": true
"WorkerGlobalScope": true,
"addEventListener": true,
"location.origin": true,
"onmessage": "write",
"postMessage": true,
"removeEventListener": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": true
}
},
"@metamask/snap-controllers>@metamask/obs-store": {
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": {
"packages": {
"@metamask/snap-controllers>@metamask/obs-store>through2": true,
"browserify>stream-browserify": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream>string_decoder": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true,
"vinyl>cloneable-readable>process-nextick-args": true
}
},
"@metamask/snap-controllers>@metamask/obs-store>through2": {
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream>string_decoder": {
"packages": {
"browserify>process": true,
"browserify>util": true,
"readable-stream": true,
"watchify>xtend": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>ajv": {
@ -3887,8 +3506,38 @@
"setTimeout": true
},
"packages": {
"json-rpc-engine>@metamask/safe-event-emitter": true,
"readable-stream": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream": {
"packages": {
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>process-nextick-args": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>string_decoder": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>process-nextick-args": {
"packages": {
"browserify>process": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": {
"packages": {
"browserify>buffer": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>string_decoder": {
"packages": {
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>nanoid": {
@ -6114,73 +5763,6 @@
"browserify>process": true
}
},
"ethjs-ens": {
"packages": {
"ethereum-ens-network-map": true,
"ethjs-ens>eth-ens-namehash": true,
"ethjs-ens>ethjs-contract": true,
"ethjs-ens>ethjs-query": true
}
},
"ethjs-ens>eth-ens-namehash": {
"globals": {
"name": "write"
},
"packages": {
"browserify>buffer": true,
"ethjs-ens>eth-ens-namehash>idna-uts46": true,
"ethjs-ens>eth-ens-namehash>js-sha3": true
}
},
"ethjs-ens>eth-ens-namehash>idna-uts46": {
"globals": {
"define": true
},
"packages": {
"browserify>punycode": true
}
},
"ethjs-ens>eth-ens-namehash>js-sha3": {
"packages": {
"browserify>process": true
}
},
"ethjs-ens>ethjs-contract": {
"packages": {
"ethjs-contract>ethjs-abi": true,
"ethjs-ens>ethjs-contract>ethjs-filter": true,
"ethjs-ens>ethjs-contract>js-sha3": true,
"ethjs>ethjs-util": true
}
},
"ethjs-ens>ethjs-contract>ethjs-filter": {
"globals": {
"clearInterval": true,
"setInterval": true
}
},
"ethjs-ens>ethjs-contract>js-sha3": {
"packages": {
"browserify>process": true
}
},
"ethjs-ens>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-ens>ethjs-query>ethjs-format": true,
"ethjs-ens>ethjs-query>ethjs-rpc": true
}
},
"ethjs-ens>ethjs-query>ethjs-format": {
"packages": {
"ethjs-ens>ethjs-query>ethjs-format>ethjs-schema": true,
"ethjs>ethjs-util": true,
"ethjs>ethjs-util>strip-hex-prefix": true,
"ethjs>number-to-bn": true
}
},
"ethjs-query": {
"globals": {
"console": true

@ -3168,43 +3168,6 @@
"watchify>xtend": true
}
},
"@metamask/post-message-stream": {
"globals": {
"addEventListener": true,
"location.origin": true,
"onmessage": "write",
"postMessage": true,
"removeEventListener": true
},
"packages": {
"@metamask/post-message-stream>readable-stream": true
}
},
"@metamask/post-message-stream>readable-stream": {
"packages": {
"@metamask/post-message-stream>readable-stream>safe-buffer": true,
"@metamask/post-message-stream>readable-stream>string_decoder": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true,
"vinyl>cloneable-readable>process-nextick-args": true
}
},
"@metamask/post-message-stream>readable-stream>safe-buffer": {
"packages": {
"browserify>buffer": true
}
},
"@metamask/post-message-stream>readable-stream>string_decoder": {
"packages": {
"@metamask/post-message-stream>readable-stream>safe-buffer": true
}
},
"@metamask/providers>@metamask/object-multiplex": {
"globals": {
"console.warn": true
@ -3217,147 +3180,13 @@
},
"@metamask/rpc-methods": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers": true,
"@metamask/controllers": true,
"@metamask/rpc-methods>@metamask/key-tree": true,
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers": true,
"eth-rpc-errors": true
}
},
"@metamask/rpc-methods>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry": true,
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/rpc-methods>@metamask/controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
}
},
"@metamask/rpc-methods>@metamask/key-tree": {
"packages": {
"@metamask/rpc-methods>@metamask/key-tree>@noble/ed25519": true,
@ -3418,148 +3247,14 @@
"setInterval": true
},
"packages": {
"@metamask/controllers": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/smart-transactions-controller>@metamask/controllers": true,
"@metamask/smart-transactions-controller>bignumber.js": true,
"@metamask/smart-transactions-controller>fast-json-patch": true,
"ethers": true,
"lodash": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry": true,
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/smart-transactions-controller>@metamask/controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>nanoid": {
"globals": {
"crypto.getRandomValues": true
@ -3582,7 +3277,6 @@
"@metamask/snap-controllers": {
"globals": {
"URL": true,
"Worker": true,
"clearTimeout": true,
"console.error": true,
"console.info": true,
@ -3595,13 +3289,13 @@
"setTimeout": true
},
"packages": {
"@metamask/post-message-stream": true,
"@metamask/controllers": true,
"@metamask/providers>@metamask/object-multiplex": true,
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers>@metamask/browser-passworder": true,
"@metamask/snap-controllers>@metamask/controllers": true,
"@metamask/snap-controllers>@metamask/execution-environments": true,
"@metamask/snap-controllers>@metamask/obs-store": true,
"@metamask/snap-controllers>@metamask/post-message-stream": true,
"@metamask/snap-controllers>ajv": true,
"@metamask/snap-controllers>concat-stream": true,
"@metamask/snap-controllers>gunzip-maybe": true,
@ -3632,153 +3326,78 @@
"browserify>buffer": true
}
},
"@metamask/snap-controllers>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry": true,
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/snap-controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry": {
"@metamask/snap-controllers>@metamask/obs-store": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": true
"@metamask/snap-controllers>@metamask/obs-store>through2": true,
"browserify>stream-browserify": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"@metamask/snap-controllers>@metamask/obs-store>through2": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream": true,
"browserify>process": true,
"browserify>util": true,
"watchify>xtend": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>process-nextick-args": true,
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>string_decoder": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>process-nextick-args": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
"browserify>process": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>string_decoder": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"@metamask/snap-controllers>@metamask/post-message-stream": {
"globals": {
"console": true
"WorkerGlobalScope": true,
"addEventListener": true,
"location.origin": true,
"onmessage": "write",
"postMessage": true,
"removeEventListener": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": true
}
},
"@metamask/snap-controllers>@metamask/obs-store": {
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": {
"packages": {
"@metamask/snap-controllers>@metamask/obs-store>through2": true,
"browserify>stream-browserify": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream>string_decoder": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true,
"vinyl>cloneable-readable>process-nextick-args": true
}
},
"@metamask/snap-controllers>@metamask/obs-store>through2": {
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream>string_decoder": {
"packages": {
"browserify>process": true,
"browserify>util": true,
"readable-stream": true,
"watchify>xtend": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>ajv": {
@ -3887,8 +3506,38 @@
"setTimeout": true
},
"packages": {
"json-rpc-engine>@metamask/safe-event-emitter": true,
"readable-stream": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream": {
"packages": {
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>process-nextick-args": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>string_decoder": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>process-nextick-args": {
"packages": {
"browserify>process": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": {
"packages": {
"browserify>buffer": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>string_decoder": {
"packages": {
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>nanoid": {
@ -6114,73 +5763,6 @@
"browserify>process": true
}
},
"ethjs-ens": {
"packages": {
"ethereum-ens-network-map": true,
"ethjs-ens>eth-ens-namehash": true,
"ethjs-ens>ethjs-contract": true,
"ethjs-ens>ethjs-query": true
}
},
"ethjs-ens>eth-ens-namehash": {
"globals": {
"name": "write"
},
"packages": {
"browserify>buffer": true,
"ethjs-ens>eth-ens-namehash>idna-uts46": true,
"ethjs-ens>eth-ens-namehash>js-sha3": true
}
},
"ethjs-ens>eth-ens-namehash>idna-uts46": {
"globals": {
"define": true
},
"packages": {
"browserify>punycode": true
}
},
"ethjs-ens>eth-ens-namehash>js-sha3": {
"packages": {
"browserify>process": true
}
},
"ethjs-ens>ethjs-contract": {
"packages": {
"ethjs-contract>ethjs-abi": true,
"ethjs-ens>ethjs-contract>ethjs-filter": true,
"ethjs-ens>ethjs-contract>js-sha3": true,
"ethjs>ethjs-util": true
}
},
"ethjs-ens>ethjs-contract>ethjs-filter": {
"globals": {
"clearInterval": true,
"setInterval": true
}
},
"ethjs-ens>ethjs-contract>js-sha3": {
"packages": {
"browserify>process": true
}
},
"ethjs-ens>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-ens>ethjs-query>ethjs-format": true,
"ethjs-ens>ethjs-query>ethjs-rpc": true
}
},
"ethjs-ens>ethjs-query>ethjs-format": {
"packages": {
"ethjs-ens>ethjs-query>ethjs-format>ethjs-schema": true,
"ethjs>ethjs-util": true,
"ethjs>ethjs-util>strip-hex-prefix": true,
"ethjs>number-to-bn": true
}
},
"ethjs-query": {
"globals": {
"console": true

@ -3168,43 +3168,6 @@
"watchify>xtend": true
}
},
"@metamask/post-message-stream": {
"globals": {
"addEventListener": true,
"location.origin": true,
"onmessage": "write",
"postMessage": true,
"removeEventListener": true
},
"packages": {
"@metamask/post-message-stream>readable-stream": true
}
},
"@metamask/post-message-stream>readable-stream": {
"packages": {
"@metamask/post-message-stream>readable-stream>safe-buffer": true,
"@metamask/post-message-stream>readable-stream>string_decoder": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true,
"vinyl>cloneable-readable>process-nextick-args": true
}
},
"@metamask/post-message-stream>readable-stream>safe-buffer": {
"packages": {
"browserify>buffer": true
}
},
"@metamask/post-message-stream>readable-stream>string_decoder": {
"packages": {
"@metamask/post-message-stream>readable-stream>safe-buffer": true
}
},
"@metamask/providers>@metamask/object-multiplex": {
"globals": {
"console.warn": true
@ -3217,147 +3180,13 @@
},
"@metamask/rpc-methods": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers": true,
"@metamask/controllers": true,
"@metamask/rpc-methods>@metamask/key-tree": true,
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers": true,
"eth-rpc-errors": true
}
},
"@metamask/rpc-methods>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry": true,
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/rpc-methods>@metamask/controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
}
},
"@metamask/rpc-methods>@metamask/key-tree": {
"packages": {
"@metamask/rpc-methods>@metamask/key-tree>@noble/ed25519": true,
@ -3418,148 +3247,14 @@
"setInterval": true
},
"packages": {
"@metamask/controllers": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/smart-transactions-controller>@metamask/controllers": true,
"@metamask/smart-transactions-controller>bignumber.js": true,
"@metamask/smart-transactions-controller>fast-json-patch": true,
"ethers": true,
"lodash": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry": true,
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/smart-transactions-controller>@metamask/controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
}
},
"@metamask/smart-transactions-controller>@metamask/controllers>nanoid": {
"globals": {
"crypto.getRandomValues": true
@ -3582,7 +3277,6 @@
"@metamask/snap-controllers": {
"globals": {
"URL": true,
"Worker": true,
"clearTimeout": true,
"console.error": true,
"console.info": true,
@ -3595,13 +3289,13 @@
"setTimeout": true
},
"packages": {
"@metamask/post-message-stream": true,
"@metamask/controllers": true,
"@metamask/providers>@metamask/object-multiplex": true,
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers>@metamask/browser-passworder": true,
"@metamask/snap-controllers>@metamask/controllers": true,
"@metamask/snap-controllers>@metamask/execution-environments": true,
"@metamask/snap-controllers>@metamask/obs-store": true,
"@metamask/snap-controllers>@metamask/post-message-stream": true,
"@metamask/snap-controllers>ajv": true,
"@metamask/snap-controllers>concat-stream": true,
"@metamask/snap-controllers>gunzip-maybe": true,
@ -3632,153 +3326,78 @@
"browserify>buffer": true
}
},
"@metamask/snap-controllers>@metamask/controllers": {
"globals": {
"Headers": true,
"URL": true,
"clearInterval": true,
"clearTimeout": true,
"console.error": true,
"console.log": true,
"fetch": true,
"setInterval": true,
"setTimeout": true
},
"packages": {
"@ethereumjs/common": true,
"@ethereumjs/tx": true,
"@metamask/contract-metadata": true,
"@metamask/controllers>abort-controller": true,
"@metamask/controllers>async-mutex": true,
"@metamask/controllers>eth-phishing-detect": true,
"@metamask/controllers>isomorphic-fetch": true,
"@metamask/controllers>multiformats": true,
"@metamask/controllers>web3-provider-engine": true,
"@metamask/metamask-eth-abis": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry": true,
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": true,
"@metamask/snap-controllers>nanoid": true,
"@storybook/api>fast-deep-equal": true,
"browserify>buffer": true,
"browserify>events": true,
"deep-freeze-strict": true,
"eth-ens-namehash": true,
"eth-json-rpc-infura": true,
"eth-keyring-controller": true,
"eth-query": true,
"eth-rpc-errors": true,
"eth-sig-util": true,
"ethereumjs-util": true,
"ethers": true,
"ethjs>ethjs-unit": true,
"immer": true,
"json-rpc-engine": true,
"jsonschema": true,
"punycode": true,
"single-call-balance-checker-abi": true,
"uuid": true,
"web3": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry": {
"@metamask/snap-controllers>@metamask/obs-store": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": true
"@metamask/snap-controllers>@metamask/obs-store>through2": true,
"browserify>stream-browserify": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": {
"globals": {
"clearInterval": true,
"setInterval": true
},
"@metamask/snap-controllers>@metamask/obs-store>through2": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-provider-http": true,
"ethjs>ethjs-unit": true,
"ethjs>ethjs-util": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream": true,
"browserify>process": true,
"browserify>util": true,
"watchify>xtend": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>process-nextick-args": true,
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>string_decoder": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>process-nextick-args": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"ethjs-query>babel-runtime": true,
"ethjs>ethjs-filter": true,
"ethjs>ethjs-util": true,
"promise-to-callback": true
"browserify>process": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": {
"@metamask/snap-controllers>@metamask/obs-store>through2>readable-stream>string_decoder": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true,
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": true,
"browserify>buffer": true,
"ethjs>number-to-bn": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": {
"@metamask/snap-controllers>@metamask/post-message-stream": {
"globals": {
"console": true
"WorkerGlobalScope": true,
"addEventListener": true,
"location.origin": true,
"onmessage": "write",
"postMessage": true,
"removeEventListener": true
},
"packages": {
"ethjs-query>babel-runtime": true,
"ethjs-query>ethjs-format": true,
"ethjs-query>ethjs-rpc": true,
"promise-to-callback": true
}
},
"@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>js-sha3": {
"packages": {
"browserify>process": true
}
},
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": {
"packages": {
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": true,
"@truffle/codec>utf8": true,
"browserify>buffer": true,
"browserify>crypto-browserify": true,
"ethereumjs-util": true,
"ethereumjs-util>ethereum-cryptography": true,
"ethereumjs-wallet>aes-js": true,
"ethereumjs-wallet>bs58check": true,
"ethereumjs-wallet>randombytes": true,
"ethers>@ethersproject/json-wallets>scrypt-js": true
}
},
"@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": {
"globals": {
"crypto": true,
"msCrypto": true
"@metamask/rpc-methods>@metamask/utils": true,
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": true
}
},
"@metamask/snap-controllers>@metamask/obs-store": {
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream": {
"packages": {
"@metamask/snap-controllers>@metamask/obs-store>through2": true,
"browserify>stream-browserify": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream>string_decoder": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true,
"vinyl>cloneable-readable>process-nextick-args": true
}
},
"@metamask/snap-controllers>@metamask/obs-store>through2": {
"@metamask/snap-controllers>@metamask/post-message-stream>readable-stream>string_decoder": {
"packages": {
"browserify>process": true,
"browserify>util": true,
"readable-stream": true,
"watchify>xtend": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>ajv": {
@ -3887,8 +3506,38 @@
"setTimeout": true
},
"packages": {
"json-rpc-engine>@metamask/safe-event-emitter": true,
"readable-stream": true
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream": true,
"json-rpc-engine>@metamask/safe-event-emitter": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream": {
"packages": {
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>process-nextick-args": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true,
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>string_decoder": true,
"@storybook/api>util-deprecate": true,
"browserify>browser-resolve": true,
"browserify>events": true,
"browserify>process": true,
"browserify>timers-browserify": true,
"pumpify>inherits": true,
"readable-stream>core-util-is": true,
"readable-stream>isarray": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>process-nextick-args": {
"packages": {
"browserify>process": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": {
"packages": {
"browserify>buffer": true
}
},
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>string_decoder": {
"packages": {
"@metamask/snap-controllers>json-rpc-middleware-stream>readable-stream>safe-buffer": true
}
},
"@metamask/snap-controllers>nanoid": {
@ -6114,73 +5763,6 @@
"browserify>process": true
}
},
"ethjs-ens": {
"packages": {
"ethereum-ens-network-map": true,
"ethjs-ens>eth-ens-namehash": true,
"ethjs-ens>ethjs-contract": true,
"ethjs-ens>ethjs-query": true
}
},
"ethjs-ens>eth-ens-namehash": {
"globals": {
"name": "write"
},
"packages": {
"browserify>buffer": true,
"ethjs-ens>eth-ens-namehash>idna-uts46": true,
"ethjs-ens>eth-ens-namehash>js-sha3": true
}
},
"ethjs-ens>eth-ens-namehash>idna-uts46": {
"globals": {
"define": true
},
"packages": {
"browserify>punycode": true
}
},
"ethjs-ens>eth-ens-namehash>js-sha3": {
"packages": {
"browserify>process": true
}
},
"ethjs-ens>ethjs-contract": {
"packages": {
"ethjs-contract>ethjs-abi": true,
"ethjs-ens>ethjs-contract>ethjs-filter": true,
"ethjs-ens>ethjs-contract>js-sha3": true,
"ethjs>ethjs-util": true
}
},
"ethjs-ens>ethjs-contract>ethjs-filter": {
"globals": {
"clearInterval": true,
"setInterval": true
}
},
"ethjs-ens>ethjs-contract>js-sha3": {
"packages": {
"browserify>process": true
}
},
"ethjs-ens>ethjs-query": {
"globals": {
"console": true
},
"packages": {
"ethjs-ens>ethjs-query>ethjs-format": true,
"ethjs-ens>ethjs-query>ethjs-rpc": true
}
},
"ethjs-ens>ethjs-query>ethjs-format": {
"packages": {
"ethjs-ens>ethjs-query>ethjs-format>ethjs-schema": true,
"ethjs>ethjs-util": true,
"ethjs>ethjs-util>strip-hex-prefix": true,
"ethjs>number-to-bn": true
}
},
"ethjs-query": {
"globals": {
"console": true

@ -17,9 +17,11 @@
"build:dev": "node development/build/index.js",
"start:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build testDev",
"benchmark:chrome": "SELENIUM_BROWSER=chrome node test/e2e/benchmark.js",
"mv3:stats:chrome": "SELENIUM_BROWSER=chrome ENABLE_MV3=true node test/e2e/mv3-perf-stats/index.js",
"benchmark:firefox": "SELENIUM_BROWSER=firefox node test/e2e/benchmark.js",
"build:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build test",
"build:test:flask": "yarn build test --build-type flask",
"build:test:mv3": "ENABLE_MV3=true yarn build test",
"test": "yarn lint && yarn test:unit && yarn test:unit:jest",
"dapp": "node development/static-server.js node_modules/@metamask/test-dapp/dist --port 8080",
"dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'",
@ -116,8 +118,8 @@
"@keystonehq/metamask-airgapped-keyring": "0.2.1",
"@material-ui/core": "^4.11.0",
"@metamask/contract-metadata": "^1.31.0",
"@metamask/controllers": "^29.0.1",
"@metamask/design-tokens": "^1.6.5",
"@metamask/controllers": "^30.0.2",
"@metamask/design-tokens": "^1.8.0",
"@metamask/eth-ledger-bridge-keyring": "^0.13.0",
"@metamask/eth-token-tracker": "^4.0.0",
"@metamask/etherscan-link": "^2.1.0",
@ -127,10 +129,10 @@
"@metamask/obs-store": "^5.0.0",
"@metamask/post-message-stream": "^4.0.0",
"@metamask/providers": "^9.0.0",
"@metamask/rpc-methods": "^0.16.0",
"@metamask/rpc-methods": "^0.18.1",
"@metamask/slip44": "^2.1.0",
"@metamask/smart-transactions-controller": "^2.1.0",
"@metamask/snap-controllers": "^0.16.0",
"@metamask/snap-controllers": "^0.18.1",
"@ngraveio/bc-ur": "^1.1.6",
"@popperjs/core": "^2.4.0",
"@reduxjs/toolkit": "^1.6.2",
@ -168,10 +170,9 @@
"ethereumjs-abi": "^0.6.4",
"ethereumjs-util": "^7.0.10",
"ethereumjs-wallet": "^0.6.4",
"ethers": "^5.0.8",
"ethers": "^5.6.4",
"ethjs": "^0.4.0",
"ethjs-contract": "^0.2.3",
"ethjs-ens": "^2.0.0",
"ethjs-query": "^0.3.4",
"extension-port-stream": "^2.0.0",
"fast-json-patch": "^2.2.1",
@ -251,7 +252,7 @@
"@metamask/eslint-config-nodejs": "^9.0.0",
"@metamask/eslint-config-typescript": "^9.0.1",
"@metamask/forwarder": "^1.1.0",
"@metamask/phishing-warning": "^1.1.0",
"@metamask/phishing-warning": "^1.2.1",
"@metamask/test-dapp": "^5.1.1",
"@sentry/cli": "^1.58.0",
"@storybook/addon-a11y": "^6.3.12",
@ -355,7 +356,7 @@
"resolve-url-loader": "^3.1.2",
"sass": "^1.32.4",
"sass-loader": "^10.1.1",
"selenium-webdriver": "^4.1.0",
"selenium-webdriver": "^4.3.1",
"semver": "^7.3.5",
"serve-handler": "^6.1.2",
"sinon": "^9.0.0",

@ -1,5 +1,5 @@
diff --git a/node_modules/abort-controller/browser.js b/node_modules/abort-controller/browser.js
index b0c5ec3..c8c8018 100644
index b0c5ec3..b61071b 100644
--- a/node_modules/abort-controller/browser.js
+++ b/node_modules/abort-controller/browser.js
@@ -2,12 +2,7 @@
@ -13,6 +13,7 @@ index b0c5ec3..c8c8018 100644
+const { AbortController } = globalThis;
/*eslint-enable @mysticatea/prettier */
module.exports = AbortController
-module.exports = AbortController
-module.exports.AbortSignal = AbortSignal
-module.exports.default = AbortController
+module.exports = { AbortController }

@ -39,11 +39,14 @@ export const MESSAGE_TYPE = {
ETH_REQUEST_ACCOUNTS: 'eth_requestAccounts',
ETH_SIGN: 'eth_sign',
ETH_SIGN_TYPED_DATA: 'eth_signTypedData',
ETH_SIGN_TYPED_DATA_V3: 'eth_signTypedData_v3',
ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4',
GET_PROVIDER_STATE: 'metamask_getProviderState',
LOG_WEB3_SHIM_USAGE: 'metamask_logWeb3ShimUsage',
PERSONAL_SIGN: 'personal_sign',
SEND_METADATA: 'metamask_sendDomainMetadata',
SWITCH_ETHEREUM_CHAIN: 'wallet_switchEthereumChain',
WALLET_REQUEST_PERMISSIONS: 'wallet_requestPermissions',
WATCH_ASSET: 'wallet_watchAsset',
WATCH_ASSET_LEGACY: 'metamask_watchAsset',
///: BEGIN:ONLY_INCLUDE_IN(flask)
@ -92,3 +95,5 @@ export const FIREFOX_BUILD_IDS = [
METAMASK_PROD_FIREFOX_ID,
METAMASK_FLASK_FIREFOX_ID,
];
export const UNKNOWN_TICKER_SYMBOL = 'UNKNOWN';

@ -1,7 +1,9 @@
import { addHexPrefix } from 'ethereumjs-util';
import { MIN_GAS_LIMIT_HEX } from '../../ui/pages/send/send.constants';
const ONE_HUNDRED_THOUSAND = 100000;
const MIN_GAS_LIMIT_DEC = '21000';
export const MIN_GAS_LIMIT_HEX = parseInt(MIN_GAS_LIMIT_DEC, 10).toString(16);
export const GAS_LIMITS = {
// maximum gasLimit of a simple send

@ -276,13 +276,23 @@ export const REJECT_NOTFICIATION_CLOSE_SIG =
*/
export const EVENT_NAMES = {
ENCRYPTION_PUBLIC_KEY_APPROVED: 'Encryption Public Key Approved',
ENCRYPTION_PUBLIC_KEY_REJECTED: 'Encryption Public Key Rejected',
ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested',
DECRYPTION_APPROVED: 'Decryption Approved',
DECRYPTION_REJECTED: 'Decryption Rejected',
DECRYPTION_REQUESTED: 'Decryption Requested',
PERMISSIONS_APPROVED: 'Permissions Approved',
PERMISSIONS_REJECTED: 'Permissions Rejected',
PERMISSIONS_REQUESTED: 'Permissions Requested',
PROVIDER_METHOD_CALLED: 'Provider Method Called',
SIGNATURE_APPROVED: 'Signature Approved',
SIGNATURE_REJECTED: 'Signature Rejected',
SIGNATURE_REQUESTED: 'Signature Requested',
TOKEN_ADDED: 'Token Added',
TOKEN_DETECTED: 'Token Detected',
TOKEN_HIDDEN: 'Token Hidden',
NFT_ADDED: 'NFT Added',
TOKEN_IMPORT_CANCELED: 'Token Import Canceled',
TOKEN_IMPORT_CLICKED: 'Token Import Clicked',
};
@ -305,6 +315,10 @@ export const EVENT = {
WALLET: 'Wallet',
},
SOURCE: {
NETWORK: {
POPULAR_NETWORK_LIST: 'popular_network_list',
CUSTOM_NETWORK_FORM: 'custom_network_form',
},
SWAPS: {
MAIN_VIEW: 'Main View',
TOKEN_VIEW: 'Token View',

@ -7,6 +7,7 @@ export const MAINNET = 'mainnet';
export const GOERLI = 'goerli';
export const LOCALHOST = 'localhost';
export const NETWORK_TYPE_RPC = 'rpc';
export const HOMESTEAD = 'homestead';
export const MAINNET_NETWORK_ID = '1';
export const ROPSTEN_NETWORK_ID = '3';
@ -55,7 +56,7 @@ export const FANTOM_DISPLAY_NAME = 'Fantom Opera';
export const HARMONY_DISPLAY_NAME = 'Harmony Mainnet Shard 0';
export const PALM_DISPLAY_NAME = 'Palm';
const infuraProjectId = process.env.INFURA_PROJECT_ID;
export const infuraProjectId = process.env.INFURA_PROJECT_ID;
export const getRpcUrl = ({ network, excludeProjectId = false }) =>
`https://${network}.infura.io/v3/${excludeProjectId ? '' : infuraProjectId}`;
@ -192,6 +193,13 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = {
[PALM_CHAIN_ID]: PALM_TOKEN_IMAGE_URL,
};
export const NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP = {
[ROPSTEN_NETWORK_ID]: ROPSTEN,
[RINKEBY_NETWORK_ID]: RINKEBY,
[GOERLI_NETWORK_ID]: GOERLI,
[MAINNET_NETWORK_ID]: HOMESTEAD,
};
export const CHAIN_ID_TO_NETWORK_ID_MAP = Object.values(
NETWORK_TYPE_TO_ID_MAP,
).reduce((chainIdToNetworkIdMap, { chainId, networkId }) => {

@ -0,0 +1,4 @@
export const PHISHING_NEW_ISSUE_URLS = {
MetaMask: 'https://github.com/metamask/eth-phishing-detect/issues/new',
PhishFort: 'https://github.com/phishfort/phishfort-lists/issues/new',
};

@ -355,3 +355,36 @@ export const ASSET_TYPES = {
COLLECTIBLE: 'COLLECTIBLE',
UNKNOWN: 'UNKNOWN',
};
export const ERC20 = 'ERC20';
export const ERC721 = 'ERC721';
export const ERC1155 = 'ERC1155';
/**
* @typedef {Object} TokenStandards
* @property {'ERC20'} ERC20 - A token that conforms to the ERC20 standard.
* @property {'ERC721'} ERC721 - A token that conforms to the ERC721 standard.
* @property {'ERC1155'} ERC1155 - A token that conforms to the ERC1155
* standard.
* @property {'NONE'} NONE - Not a token, but rather the base asset of the
* selected chain.
*/
/**
* This type will work anywhere you expect a string that can be one of the
* above statuses
*
* @typedef {TokenStandards[keyof TokenStandards]} TokenStandardStrings
*/
/**
* Describes the standard which a token conforms to.
*
* @type {TokenStandards}
*/
export const TOKEN_STANDARDS = {
ERC20,
ERC721,
ERC1155,
NONE: 'NONE',
};

@ -1,6 +1,7 @@
import { memoize } from 'lodash';
import { SECOND } from '../constants/time';
const getFetchWithTimeout = memoize((timeout) => {
const getFetchWithTimeout = memoize((timeout = SECOND * 30) => {
if (!Number.isInteger(timeout) || timeout < 1) {
throw new Error('Must specify positive integer timeout.');
}

@ -6,7 +6,7 @@ describe('getFetchWithTimeout', () => {
it('fetches a url', async () => {
nock('https://api.infura.io').get('/money').reply(200, '{"hodl": false}');
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
const response = await (
await fetchWithTimeout('https://api.infura.io/money')
).json();
@ -46,15 +46,9 @@ describe('getFetchWithTimeout', () => {
});
it('throws on invalid timeout', async () => {
await expect(() => getFetchWithTimeout()).toThrow(
'Must specify positive integer timeout.',
);
await expect(() => getFetchWithTimeout(-1)).toThrow(
'Must specify positive integer timeout.',
);
await expect(() => getFetchWithTimeout({})).toThrow(
'Must specify positive integer timeout.',
);
await expect(() => getFetchWithTimeout(true)).toThrow(
'Must specify positive integer timeout.',
);

@ -1,7 +1,6 @@
import { SECOND } from '../constants/time';
import getFetchWithTimeout from './fetch-with-timeout';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
/**
* Makes a JSON RPC request to the given URL, with the given RPC method and params.

@ -2,8 +2,11 @@ import { isHexString } from 'ethereumjs-util';
import { ethers } from 'ethers';
import { abiERC721, abiERC20, abiERC1155 } from '@metamask/metamask-eth-abis';
import log from 'loglevel';
import { TOKEN_STANDARDS } from '../../ui/helpers/constants/common';
import { ASSET_TYPES, TRANSACTION_TYPES } from '../constants/transaction';
import {
ASSET_TYPES,
TOKEN_STANDARDS,
TRANSACTION_TYPES,
} from '../constants/transaction';
import { readAddressAsContract } from './contract-utils';
import { isEqualCaseInsensitive } from './string-utils';

@ -66,9 +66,13 @@ export const UI_NOTIFICATIONS = {
width: '100%',
},
},
13: {
id: 13,
date: '2022-07-12',
},
};
export const getTranslatedUINoficiations = (t, locale) => {
export const getTranslatedUINotifications = (t, locale) => {
const formattedLocale = locale.replace('_', '-');
return {
1: {
@ -182,5 +186,14 @@ export const getTranslatedUINoficiations = (t, locale) => {
new Date(UI_NOTIFICATIONS[12].date),
),
},
13: {
...UI_NOTIFICATIONS[13],
title: t('notifications13Title'),
description: t('notifications13Description'),
actionText: t('notifications13ActionText'),
date: new Intl.DateTimeFormat(formattedLocale).format(
new Date(UI_NOTIFICATIONS[13].date),
),
},
};
};

@ -1,12 +1,16 @@
#!/usr/bin/env node
const path = require('path');
const { promises: fs, constants: fsConstants } = require('fs');
const { promises: fs } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const ttest = require('ttest');
const { retry } = require('../../development/lib/retry');
const { exitWithError } = require('../../development/lib/exit-with-error');
const {
isWritable,
getFirstParentDirectoryThatExists,
} = require('../helpers/file');
const { withFixtures, tinyDelayMs } = require('./helpers');
const { PAGES } = require('./webdriver/driver');
@ -108,35 +112,6 @@ async function profilePageLoad(pages, numSamples, retries) {
return results;
}
async function isWritable(directory) {
try {
await fs.access(directory, fsConstants.W_OK);
return true;
} catch (error) {
if (error.code !== 'EACCES') {
throw error;
}
return false;
}
}
async function getFirstParentDirectoryThatExists(directory) {
let nextDirectory = directory;
for (;;) {
try {
await fs.access(nextDirectory, fsConstants.F_OK);
return nextDirectory;
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
} else if (nextDirectory === path.dirname(nextDirectory)) {
throw new Error('Failed to find parent directory that exists');
}
nextDirectory = path.dirname(nextDirectory);
}
}
}
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',

@ -69,6 +69,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -59,6 +59,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -55,6 +55,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -73,6 +73,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -56,6 +56,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -56,6 +56,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -110,6 +110,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -55,6 +55,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -55,6 +55,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -59,6 +59,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -55,6 +55,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -30,6 +30,9 @@
"notifications": {
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -56,6 +56,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -56,6 +56,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -55,6 +55,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -66,6 +66,9 @@
},
"12": {
"isShown": true
},
"13": {
"isShown": true
}
}
},

@ -9,6 +9,7 @@ const FixtureServer = require('./fixture-server');
const PhishingWarningPageServer = require('./phishing-warning-page-server');
const { buildWebDriver } = require('./webdriver');
const { ensureXServerIsRunning } = require('./x-server');
const GanacheSeeder = require('./seeder/ganache-seeder');
const tinyDelayMs = 200;
const regularDelayMs = tinyDelayMs * 2;
@ -23,6 +24,7 @@ async function withFixtures(options, testSuite) {
dapp,
fixtures,
ganacheOptions,
smartContract,
driverOptions,
dappOptions,
title,
@ -46,6 +48,14 @@ async function withFixtures(options, testSuite) {
let failed = false;
try {
await ganacheServer.start(ganacheOptions);
let contractRegistry;
if (smartContract) {
const ganacheSeeder = new GanacheSeeder(true);
await ganacheSeeder.deploySmartContract(smartContract);
contractRegistry = ganacheSeeder.getContractRegistry();
}
if (ganacheOptions?.concurrent) {
const { port, chainId } = ganacheOptions.concurrent;
secondaryGanacheServer = new Ganache();
@ -100,6 +110,7 @@ async function withFixtures(options, testSuite) {
await testSuite({
driver,
mockServer,
contractRegistry,
});
if (process.env.SELENIUM_BROWSER === 'chrome') {

@ -0,0 +1,140 @@
#!/usr/bin/env node
/* eslint-disable node/shebang */
const path = require('path');
const { promises: fs, constants: fsConstants } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const { exitWithError } = require('../../development/lib/exit-with-error');
const { withFixtures, tinyDelayMs } = require('./helpers');
async function measurePage() {
let metrics;
try {
await withFixtures({ fixtures: 'imported-account' }, async ({ driver }) => {
await driver.delay(tinyDelayMs);
await driver.navigate();
await driver.findElement('#password');
await driver.delay(1000);
const logs = await driver.checkBrowserForLavamoatLogs();
let logString = '';
let inObject = false;
const parsedLogs = [];
logs.forEach((log) => {
if (log.indexOf('"version": 1') >= 0) {
logString += log;
parsedLogs.push(`{${logString}}`);
logString = '';
inObject = false;
} else if (inObject) {
logString += log;
} else if (
log.search(/"name": ".*app\/scripts\/background.js",/u) >= 0 ||
log.search(/"name": ".*app\/scripts\/ui.js",/u) >= 0
) {
logString += log;
inObject = true;
}
});
metrics = parsedLogs.map((pl) => JSON.parse(pl));
});
} catch (error) {
// do nothing
}
return metrics;
}
async function profilePageLoad() {
const results = await measurePage();
const metrics = {};
metrics['background.js'] = results[0];
metrics['ui.js'] = results[1];
return metrics;
}
async function isWritable(directory) {
try {
await fs.access(directory, fsConstants.W_OK);
return true;
} catch (error) {
if (error.code !== 'EACCES') {
throw error;
}
return false;
}
}
async function getFirstParentDirectoryThatExists(directory) {
let nextDirectory = directory;
for (;;) {
try {
await fs.access(nextDirectory, fsConstants.F_OK);
return nextDirectory;
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
} else if (nextDirectory === path.dirname(nextDirectory)) {
throw new Error('Failed to find parent directory that exists');
}
nextDirectory = path.dirname(nextDirectory);
}
}
}
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',
'Run a page load benchmark',
(_yargs) =>
_yargs.option('out', {
description:
'Output filename. Output printed to STDOUT of this is omitted.',
type: 'string',
normalize: true,
}),
);
const { out } = argv;
let outputDirectory;
let existingParentDirectory;
if (out) {
outputDirectory = path.dirname(out);
existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error('Specified output file directory is not writable');
}
}
const results = await profilePageLoad();
if (out) {
if (outputDirectory !== existingParentDirectory) {
await fs.mkdir(outputDirectory, { recursive: true });
}
await fs.writeFile(
path.join(out, 'background.json'),
JSON.stringify(results['background.js'], null, 2),
);
await fs.writeFile(
path.join(out, 'ui.json'),
JSON.stringify(results['ui.js'], null, 2),
);
} else {
console.log(JSON.stringify(results, null, 2));
}
}
main().catch((error) => {
exitWithError(error);
});

@ -176,6 +176,35 @@ async function setupMocking(server, testSpecificMock) {
};
});
await server
.forGet('https://token-api.metaswap.codefi.network/token/0x539')
.thenCallback(() => {
return {
statusCode: 200,
json: {},
};
});
await server
.forGet(
'https://static.metaswap.codefi.network/api/v1/tokenIcons/1337/0x0d8775f648430679a709e98d2b0cb6250d2887ef.png',
)
.thenCallback(() => {
return {
statusCode: 200,
};
});
await server
.forGet(
'https://static.metaswap.codefi.network/api/v1/tokenIcons/1337/0x2efa2cb29c2341d8e5ba7d3262c9e9d6f1bf3711.png',
)
.thenCallback(() => {
return {
statusCode: 200,
};
});
testSpecificMock(server);
}

@ -0,0 +1,119 @@
#!/usr/bin/env node
/* eslint-disable node/shebang */
const path = require('path');
const { promises: fs } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const {
isWritable,
getFirstParentDirectoryThatExists,
} = require('../../helpers/file');
const { exitWithError } = require('../../../development/lib/exit-with-error');
/**
* The e2e test case is used to capture bundle time statistics for extension.
*/
const backgroundFiles = [
'runtime-lavamoat.js',
'lockdown-more.js',
'globalthis.js',
'sentry-install.js',
'policy-load.js',
];
const uiFiles = [
'globalthis.js',
'sentry-install.js',
'runtime-lavamoat.js',
'lockdown-more.js',
'policy-load.js',
];
const BackgroundFileRegex = /background-[0-9]*.js/u;
const CommonFileRegex = /common-[0-9]*.js/u;
const UIFileRegex = /ui-[0-9]*.js/u;
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',
'Run a page load benchmark',
(_yargs) =>
_yargs.option('out', {
description:
'Output filename. Output printed to STDOUT of this is omitted.',
type: 'string',
normalize: true,
}),
);
const { out } = argv;
const distFolder = 'dist/chrome';
const backgroundFileList = [];
const uiFileList = [];
const files = await fs.readdir(distFolder);
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (CommonFileRegex.test(file)) {
const stats = await fs.stat(`${distFolder}/${file}`);
backgroundFileList.push({ name: file, size: stats.size });
uiFileList.push({ name: file, size: stats.size });
} else if (
backgroundFiles.includes(file) ||
BackgroundFileRegex.test(file)
) {
const stats = await fs.stat(`${distFolder}/${file}`);
backgroundFileList.push({ name: file, size: stats.size });
} else if (uiFiles.includes(file) || UIFileRegex.test(file)) {
const stats = await fs.stat(`${distFolder}/${file}`);
uiFileList.push({ name: file, size: stats.size });
}
}
const backgroundBundleSize = backgroundFileList.reduce(
(result, file) => result + file.size,
0,
);
const uiBundleSize = uiFileList.reduce(
(result, file) => result + file.size,
0,
);
const result = {
background: {
name: 'background',
size: backgroundBundleSize,
fileList: backgroundFileList,
},
ui: {
name: 'ui',
size: uiBundleSize,
fileList: uiFileList,
},
};
if (out) {
const outPath = `${out}/bundle_size.json`;
const outputDirectory = path.dirname(outPath);
const existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error('Specified output file directory is not writable');
}
if (outputDirectory !== existingParentDirectory) {
await fs.mkdir(outputDirectory, { recursive: true });
}
await fs.writeFile(outPath, JSON.stringify(result, null, 2));
} else {
console.log(JSON.stringify(result, null, 2));
}
}
main().catch((error) => {
exitWithError(error);
});

@ -0,0 +1,2 @@
require('./init-load-stats');
require('./bundle-size');

@ -0,0 +1,111 @@
#!/usr/bin/env node
/* eslint-disable node/shebang */
const path = require('path');
const { promises: fs } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const { exitWithError } = require('../../../development/lib/exit-with-error');
const {
isWritable,
getFirstParentDirectoryThatExists,
} = require('../../helpers/file');
const { withFixtures, tinyDelayMs } = require('../helpers');
/**
* The e2e test case is used to capture load and initialisation time statistics for extension in MV3 environment.
*/
async function profilePageLoad() {
const parsedLogs = {};
try {
await withFixtures({ fixtures: 'imported-account' }, async ({ driver }) => {
await driver.delay(tinyDelayMs);
await driver.navigate();
await driver.delay(1000);
const logs = await driver.checkBrowserForLavamoatLogs();
let logString = '';
let logType = '';
logs.forEach((log) => {
if (log.indexOf('"version": 1') >= 0) {
// log end here
logString += log;
parsedLogs[logType] = JSON.parse(`{${logString}}`);
logString = '';
logType = '';
} else if (logType) {
// log string continues
logString += log;
} else if (
log.search(/"name": ".*app\/scripts\/background.js",/u) >= 0
) {
// background log starts
logString += log;
logType = 'background';
} else if (log.search(/"name": ".*app\/scripts\/ui.js",/u) >= 0) {
// ui log starts
logString += log;
logType = 'ui';
} else if (log.search(/"name": "Total"/u) >= 0) {
// load time log starts
logString += log;
logType = 'loadTime';
}
});
});
} catch (error) {
console.log('Error in trying to parse logs.');
}
return parsedLogs;
}
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',
'Run a page load benchmark',
(_yargs) =>
_yargs.option('out', {
description:
'Output filename. Output printed to STDOUT of this is omitted.',
type: 'string',
normalize: true,
}),
);
const results = await profilePageLoad();
const { out } = argv;
const logCategories = [
{ key: 'background', dirPath: 'initialisation/background/stacks.json' },
{ key: 'ui', dirPath: 'initialisation/ui/stacks.json' },
{ key: 'loadTime', dirPath: 'load_time/stats.json' },
];
if (out) {
logCategories.forEach(async ({ key, dirPath }) => {
if (results[key]) {
const outPath = `${out}/${dirPath}`;
const outputDirectory = path.dirname(outPath);
const existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error('Specified output file directory is not writable');
}
if (outputDirectory !== existingParentDirectory) {
await fs.mkdir(outputDirectory, { recursive: true });
}
await fs.writeFile(outPath, JSON.stringify(results[key], null, 2));
}
});
} else {
console.log(JSON.stringify(results, null, 2));
}
}
main().catch((error) => {
exitWithError(error);
});

@ -0,0 +1,111 @@
#!/usr/bin/env node
/* eslint-disable node/shebang */
const path = require('path');
const { promises: fs } = require('fs');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const { exitWithError } = require('../../development/lib/exit-with-error');
const {
isWritable,
getFirstParentDirectoryThatExists,
} = require('../helpers/file');
const { withFixtures, tinyDelayMs } = require('./helpers');
/**
* The e2e test case is used to capture load and initialisation time statistics for extension in MV3 environment.
*/
async function profilePageLoad() {
const parsedLogs = {};
try {
await withFixtures({ fixtures: 'imported-account' }, async ({ driver }) => {
await driver.delay(tinyDelayMs);
await driver.navigate();
await driver.delay(1000);
const logs = await driver.checkBrowserForLavamoatLogs();
let logString = '';
let logType = '';
logs.forEach((log) => {
if (log.indexOf('"version": 1') >= 0) {
// log end here
logString += log;
parsedLogs[logType] = JSON.parse(`{${logString}}`);
logString = '';
logType = '';
} else if (logType) {
// log string continues
logString += log;
} else if (
log.search(/"name": ".*app\/scripts\/background.js",/u) >= 0
) {
// background log starts
logString += log;
logType = 'background';
} else if (log.search(/"name": ".*app\/scripts\/ui.js",/u) >= 0) {
// ui log starts
logString += log;
logType = 'ui';
} else if (log.search(/"name": "Total"/u) >= 0) {
// load time log starts
logString += log;
logType = 'loadTime';
}
});
});
} catch (error) {
console.log('Error in trying to parse logs.');
}
return parsedLogs;
}
async function main() {
const { argv } = yargs(hideBin(process.argv)).usage(
'$0 [options]',
'Run a page load benchmark',
(_yargs) =>
_yargs.option('out', {
description:
'Output filename. Output printed to STDOUT of this is omitted.',
type: 'string',
normalize: true,
}),
);
const results = await profilePageLoad();
const { out } = argv;
const logCategories = [
{ key: 'background', dirPath: 'initialisation/background/stacks.json' },
{ key: 'ui', dirPath: 'initialisation/ui/stacks.json' },
{ key: 'loadTime', dirPath: 'load_time/stats.json' },
];
if (out) {
logCategories.forEach(async ({ key, dirPath }) => {
if (results[key]) {
const outPath = `${out}/${dirPath}`;
const outputDirectory = path.dirname(outPath);
const existingParentDirectory = await getFirstParentDirectoryThatExists(
outputDirectory,
);
if (!(await isWritable(existingParentDirectory))) {
throw new Error('Specified output file directory is not writable');
}
if (outputDirectory !== existingParentDirectory) {
await fs.mkdir(outputDirectory, { recursive: true });
}
await fs.writeFile(outPath, JSON.stringify(results[key], null, 2));
}
});
} else {
console.log(JSON.stringify(results, null, 2));
}
}
main().catch((error) => {
exitWithError(error);
});

@ -70,10 +70,12 @@ async function main() {
}
let testTimeoutInMilliseconds = 60 * 1000;
let exit = '--exit';
if (leaveRunning) {
process.env.E2E_LEAVE_RUNNING = 'true';
testTimeoutInMilliseconds = 0;
exit = '--no-exit';
}
await retry({ retries }, async () => {
@ -83,6 +85,7 @@ async function main() {
'--timeout',
testTimeoutInMilliseconds,
e2eTestPath,
exit,
]);
});
}

@ -0,0 +1,28 @@
/*
* Use this class to store pre-deployed smart contract addresses of the contracts deployed to
* a local blockchain instance ran by Ganache.
*/
class GanacheContractAddressRegistry {
#addresses = {};
/**
* Store new contract address in key:value pair.
*
* @param contractName
* @param contractAddress
*/
storeNewContractAddress(contractName, contractAddress) {
this.#addresses[contractName] = contractAddress;
}
/**
* Get deployed contract address by its name (key).
*
* @param contractName
*/
getContractAddress(contractName) {
return this.#addresses[contractName];
}
}
module.exports = GanacheContractAddressRegistry;

@ -0,0 +1,88 @@
const { ethers } = require('ethers');
const ganache = require('ganache');
const { contractConfiguration } = require('./smart-contracts');
const GanacheContractAddressRegistry = require('./ganache-contract-address-registry');
/*
* Ganache seeder is used to seed initial smart contract or set initial blockchain state.
*/
class GanacheSeeder {
constructor(debug = false) {
this.debug = debug;
this.smartContractRegistry = new GanacheContractAddressRegistry();
}
/**
* Deploy initial smart contracts that can be used later within the e2e tests.
*
* @param contractName
*/
async deploySmartContract(contractName) {
if (this.debug) {
console.log('Deploying smart contracts using GanacheSeeder');
}
const ethersProvider = new ethers.providers.Web3Provider(
ganache.provider(),
'any',
);
const contractFactory = new ethers.ContractFactory(
contractConfiguration[contractName].abi,
contractConfiguration[contractName].bytecode,
ethersProvider.getSigner(),
);
let contract;
if (contractName === 'hst') {
contract = await contractFactory.deploy(
contractConfiguration.hst.initialAmount,
contractConfiguration.hst.tokenName,
contractConfiguration.hst.decimalUnits,
contractConfiguration.hst.tokenSymbol,
);
} else {
contract = await contractFactory.deploy();
}
await contract.deployTransaction.wait();
if (this.debug) {
console.log(
`Contract mined! address: ${contract.address} transactionHash: ${contract.deployTransaction.hash}`,
);
}
this.storeSmartContractAddress(contractName, contract.address);
}
/**
* Store deployed smart contract address within the environment variables
* to make it available everywhere.
*
* @param contractName
* @param contractAddress
*/
storeSmartContractAddress(contractName, contractAddress) {
if (this.debug) {
console.log(
`Storing smart contract address: [${contractName}] => ${contractAddress}`,
);
}
this.smartContractRegistry.storeNewContractAddress(
contractName,
contractAddress,
);
}
/**
* Return an instance of the currently used smart contract registry.
*
* @returns GanacheContractAddressRegistry
*/
getContractRegistry() {
return this.smartContractRegistry;
}
}
module.exports = GanacheSeeder;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save