mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 18:00:18 +01:00
Merge remote-tracking branch 'origin/develop' into master-sync
This commit is contained in:
commit
f19173b0f2
@ -6,13 +6,13 @@ set -x
|
||||
set -o pipefail
|
||||
|
||||
# use `improved-yarn-audit` since that allows for exclude
|
||||
# exclude 1002401 until we remove use of 3Box, 1002581 until we can find a better solution
|
||||
yarn run improved-yarn-audit --ignore-dev-deps --min-severity moderate --exclude GHSA-93q8-gq69-wqmw,GHSA-257v-vj4p-3w2h,GHSA-fwr7-v2mv-hh25
|
||||
audit_status="$?"
|
||||
# exclusions are in .iyarc now
|
||||
yarn run improved-yarn-audit \
|
||||
--ignore-dev-deps \
|
||||
--min-severity moderate \
|
||||
--fail-on-missing-exclusions
|
||||
|
||||
# Use a bitmask to ignore INFO and LOW severity audit results
|
||||
# See here: https://yarnpkg.com/lang/en/docs/cli/audit/
|
||||
audit_status="$(( audit_status & 11100 ))"
|
||||
audit_status="$?"
|
||||
|
||||
if [[ "$audit_status" != 0 ]]
|
||||
then
|
||||
|
@ -44,14 +44,6 @@ module.exports = {
|
||||
path.resolve(__dirname, '.eslintrc.babel.js'),
|
||||
path.resolve(__dirname, '.eslintrc.typescript-compat.js'),
|
||||
],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: {
|
||||
// This rule does not work with CommonJS modules. We will just have to
|
||||
// trust that all of the files specified above are indeed modules.
|
||||
'import/unambiguous': 'off',
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
// When determining the location of a `require()` call, use Node's
|
||||
|
2
.github/workflows/crowdin_action.yml
vendored
2
.github/workflows/crowdin_action.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: crowdin action
|
||||
uses: crowdin/github-action@9237b4cb361788dfce63feb2e2f15c09e2fe7415
|
||||
uses: crowdin/github-action@a3160b9e5a9e00739392c23da5e580c6cabe526d
|
||||
with:
|
||||
upload_translations: true
|
||||
download_translations: true
|
||||
|
4
.iyarc
Normal file
4
.iyarc
Normal file
@ -0,0 +1,4 @@
|
||||
# improved-yarn-audit advisory exclusions
|
||||
GHSA-93q8-gq69-wqmw
|
||||
GHSA-257v-vj4p-3w2h
|
||||
GHSA-fwr7-v2mv-hh25
|
@ -1248,20 +1248,7 @@ const state = {
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://metamask.io',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
jsonrpc: '2.0',
|
||||
id: 522690215,
|
||||
origin: 'https://metamask.io',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1602643170686,
|
||||
response: {
|
||||
id: 522690215,
|
||||
jsonrpc: '2.0',
|
||||
result: [],
|
||||
},
|
||||
responseTime: 1602643170688,
|
||||
success: true,
|
||||
},
|
||||
@ -1270,20 +1257,7 @@ const state = {
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://widget.getacute.io',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
jsonrpc: '2.0',
|
||||
id: 1620464600,
|
||||
origin: 'https://widget.getacute.io',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1602643172935,
|
||||
response: {
|
||||
id: 1620464600,
|
||||
jsonrpc: '2.0',
|
||||
result: [],
|
||||
},
|
||||
responseTime: 1602643172935,
|
||||
success: true,
|
||||
},
|
||||
@ -1292,19 +1266,7 @@ const state = {
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100021,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710669962,
|
||||
response: {
|
||||
id: 4279100021,
|
||||
jsonrpc: '2.0',
|
||||
result: [],
|
||||
},
|
||||
responseTime: 1620710669963,
|
||||
success: true,
|
||||
},
|
||||
@ -1313,19 +1275,7 @@ const state = {
|
||||
method: 'eth_requestAccounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_requestAccounts',
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100022,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710686872,
|
||||
response: {
|
||||
id: 4279100022,
|
||||
jsonrpc: '2.0',
|
||||
result: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'],
|
||||
},
|
||||
responseTime: 1620710693187,
|
||||
success: true,
|
||||
},
|
||||
@ -1334,19 +1284,7 @@ const state = {
|
||||
method: 'eth_requestAccounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_requestAccounts',
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100023,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710693204,
|
||||
response: {
|
||||
id: 4279100023,
|
||||
jsonrpc: '2.0',
|
||||
result: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'],
|
||||
},
|
||||
responseTime: 1620710693213,
|
||||
success: true,
|
||||
},
|
||||
@ -1355,20 +1293,7 @@ const state = {
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100034,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710712072,
|
||||
response: {
|
||||
id: 4279100034,
|
||||
jsonrpc: '2.0',
|
||||
result: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'],
|
||||
},
|
||||
responseTime: 1620710712075,
|
||||
success: true,
|
||||
},
|
||||
|
18
README.md
18
README.md
@ -60,9 +60,23 @@ You can run the linter by itself with `yarn lint`, and you can automatically fix
|
||||
|
||||
Our e2e test suite can be run on either Firefox or Chrome. In either case, start by creating a test build by running `yarn build:test`.
|
||||
|
||||
Firefox e2e tests can be run with `yarn test:e2e:firefox`.
|
||||
- Firefox e2e tests can be run with `yarn test:e2e:firefox`.
|
||||
|
||||
Chrome e2e tests can be run with `yarn test:e2e:chrome`, but they will only work if you have Chrome v79 installed. Update the `chromedriver` package to a version matching your local Chrome installation to run e2e tests on newer Chrome versions.
|
||||
- Chrome e2e tests can be run with `yarn test:e2e:chrome`. The `chromedriver` package major version must match the major version of your local Chrome installation. If they don't match, update whichever is behind before running Chrome e2e tests.
|
||||
|
||||
- Single e2e tests can be run with `yarn test:e2e:single test/e2e/tests/TEST_NAME.spec.js` along with the options below.
|
||||
|
||||
```console
|
||||
--browser Set the browser used; either 'chrome' or 'firefox'.
|
||||
|
||||
--leave-running Leaves the browser running after a test fails, along with anything else
|
||||
that the test used (ganache, the test dapp, etc.).
|
||||
|
||||
--retries Set how many times the test should be retried upon failure. Default is 0.
|
||||
```
|
||||
|
||||
An example for running `account-details` testcase with chrome and leaving the browser open would be:
|
||||
`yarn test:e2e:single test/e2e/tests/account-details.spec.js --browser=chrome --leave-running`
|
||||
|
||||
### Changing dependencies
|
||||
|
||||
|
651
app/_locales/de/messages.json
generated
651
app/_locales/de/messages.json
generated
File diff suppressed because it is too large
Load Diff
639
app/_locales/el/messages.json
generated
639
app/_locales/el/messages.json
generated
File diff suppressed because it is too large
Load Diff
32
app/_locales/en/messages.json
generated
32
app/_locales/en/messages.json
generated
@ -160,6 +160,10 @@
|
||||
"addNetwork": {
|
||||
"message": "Add Network"
|
||||
},
|
||||
"addNetworkTooltipWarning": {
|
||||
"message": "This network connection relies on third parties. This connection may be less reliable or enable third-parties to track activity. $1",
|
||||
"description": "$1 is Learn more link"
|
||||
},
|
||||
"addSuggestedTokens": {
|
||||
"message": "Add Suggested Tokens"
|
||||
},
|
||||
@ -734,9 +738,6 @@
|
||||
"customGasSubTitle": {
|
||||
"message": "Increasing fee may decrease processing times, but it is not guaranteed."
|
||||
},
|
||||
"customNetworks": {
|
||||
"message": "Custom networks"
|
||||
},
|
||||
"customSpendLimit": {
|
||||
"message": "Custom Spend Limit"
|
||||
},
|
||||
@ -804,9 +805,6 @@
|
||||
"decryptRequest": {
|
||||
"message": "Decrypt request"
|
||||
},
|
||||
"defaultTheme": {
|
||||
"message": "Default"
|
||||
},
|
||||
"delete": {
|
||||
"message": "Delete"
|
||||
},
|
||||
@ -1251,6 +1249,10 @@
|
||||
"message": "All Flask APIs are experimental. They may be changed or removed without notice, or they might stay on Flask indefinitely without ever being migrated to stable MetaMask. Use them at your own risk.",
|
||||
"description": "This message warns developers about unstable Flask APIs"
|
||||
},
|
||||
"flaskWelcomeWarning4": {
|
||||
"message": "Make sure to disable your regular MetaMask extension when using Flask.",
|
||||
"description": "This message calls to pay attention about multiple versions of MetaMask running on the same site (Flask + Prod)"
|
||||
},
|
||||
"flaskWelcomeWarningAcceptButton": {
|
||||
"message": "I accept the risks",
|
||||
"description": "this text is shown on a button, which the user presses to confirm they understand the risks of using Flask"
|
||||
@ -1442,6 +1444,9 @@
|
||||
"hide": {
|
||||
"message": "Hide"
|
||||
},
|
||||
"hideFullTransactionDetails": {
|
||||
"message": "Hide full transaction details"
|
||||
},
|
||||
"hideSeedPhrase": {
|
||||
"message": "Hide seed phrase"
|
||||
},
|
||||
@ -1714,6 +1719,9 @@
|
||||
"levelArrow": {
|
||||
"message": "level arrow"
|
||||
},
|
||||
"lightTheme": {
|
||||
"message": "Light"
|
||||
},
|
||||
"likeToImportTokens": {
|
||||
"message": "Would you like to import these tokens?"
|
||||
},
|
||||
@ -2299,9 +2307,6 @@
|
||||
"onlyConnectTrust": {
|
||||
"message": "Only connect with sites you trust."
|
||||
},
|
||||
"onlyInteractWith": {
|
||||
"message": "Only interact with entities you trust."
|
||||
},
|
||||
"openFullScreenForLedgerWebHid": {
|
||||
"message": "Open MetaMask in full screen to connect your ledger via WebHID.",
|
||||
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
|
||||
@ -2321,6 +2326,9 @@
|
||||
"origin": {
|
||||
"message": "Origin"
|
||||
},
|
||||
"osTheme": {
|
||||
"message": "System"
|
||||
},
|
||||
"padlock": {
|
||||
"message": "Padlock"
|
||||
},
|
||||
@ -2423,6 +2431,9 @@
|
||||
"message": "+ $1 more",
|
||||
"description": "$1 is a number of additional but unshown items in a list- this message will be shown in place of those items"
|
||||
},
|
||||
"popularCustomNetworks": {
|
||||
"message": "Popular custom networks"
|
||||
},
|
||||
"preferredLedgerConnectionType": {
|
||||
"message": "Preferred Ledger Connection Type",
|
||||
"description": "A header for a dropdown in the advanced section of settings. Appears above the ledgerConnectionPreferenceDescription message"
|
||||
@ -3926,6 +3937,9 @@
|
||||
"walletCreationSuccessTitle": {
|
||||
"message": "Wallet creation successful"
|
||||
},
|
||||
"warning": {
|
||||
"message": "Warning"
|
||||
},
|
||||
"weak": {
|
||||
"message": "Weak"
|
||||
},
|
||||
|
1743
app/_locales/es/messages.json
generated
1743
app/_locales/es/messages.json
generated
File diff suppressed because it is too large
Load Diff
637
app/_locales/fr/messages.json
generated
637
app/_locales/fr/messages.json
generated
File diff suppressed because it is too large
Load Diff
641
app/_locales/hi/messages.json
generated
641
app/_locales/hi/messages.json
generated
File diff suppressed because it is too large
Load Diff
641
app/_locales/id/messages.json
generated
641
app/_locales/id/messages.json
generated
File diff suppressed because it is too large
Load Diff
639
app/_locales/ja/messages.json
generated
639
app/_locales/ja/messages.json
generated
File diff suppressed because it is too large
Load Diff
637
app/_locales/ko/messages.json
generated
637
app/_locales/ko/messages.json
generated
File diff suppressed because it is too large
Load Diff
3600
app/_locales/pt/messages.json
generated
3600
app/_locales/pt/messages.json
generated
File diff suppressed because it is too large
Load Diff
641
app/_locales/ru/messages.json
generated
641
app/_locales/ru/messages.json
generated
File diff suppressed because it is too large
Load Diff
685
app/_locales/tl/messages.json
generated
685
app/_locales/tl/messages.json
generated
File diff suppressed because it is too large
Load Diff
643
app/_locales/tr/messages.json
generated
643
app/_locales/tr/messages.json
generated
File diff suppressed because it is too large
Load Diff
637
app/_locales/vi/messages.json
generated
637
app/_locales/vi/messages.json
generated
File diff suppressed because it is too large
Load Diff
3993
app/_locales/zh/messages.json
generated
Normal file
3993
app/_locales/zh/messages.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
app/images/bsc-filled.svg
Normal file
1
app/images/bsc-filled.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 10 KiB |
1
app/images/palm.svg
Normal file
1
app/images/palm.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 314 KiB |
@ -1,4 +1,13 @@
|
||||
import { isEqual, merge, omit, omitBy, pickBy, size, sum } from 'lodash';
|
||||
import {
|
||||
isEqual,
|
||||
memoize,
|
||||
merge,
|
||||
omit,
|
||||
omitBy,
|
||||
pickBy,
|
||||
size,
|
||||
sum,
|
||||
} from 'lodash';
|
||||
import { ObservableStore } from '@metamask/obs-store';
|
||||
import { bufferToHex, keccak } from 'ethereumjs-util';
|
||||
import { generateUUID } from 'pubnub';
|
||||
@ -540,9 +549,7 @@ export default class MetaMetricsController {
|
||||
* @returns {MetaMetricsTraits | null} traits that have changed since last update
|
||||
*/
|
||||
_buildUserTraitsObject(metamaskState) {
|
||||
/**
|
||||
* @type {MetaMetricsTraits}
|
||||
*/
|
||||
/** @type {MetaMetricsTraits} */
|
||||
const currentTraits = {
|
||||
[TRAITS.ADDRESS_BOOK_ENTRIES]: sum(
|
||||
Object.values(metamaskState.addressBook).map(size),
|
||||
@ -554,9 +561,12 @@ export default class MetaMetricsController {
|
||||
[TRAITS.NFT_AUTODETECTION_ENABLED]: metamaskState.useCollectibleDetection,
|
||||
[TRAITS.NUMBER_OF_ACCOUNTS]: Object.values(metamaskState.identities)
|
||||
.length,
|
||||
[TRAITS.NUMBER_OF_NFT_COLLECTIONS]: this._getNumberOfNFtCollection(
|
||||
metamaskState,
|
||||
[TRAITS.NUMBER_OF_NFT_COLLECTIONS]: this._getAllUniqueNFTAddressesLength(
|
||||
metamaskState.allCollectibles,
|
||||
),
|
||||
[TRAITS.NUMBER_OF_NFTS]: this._getAllNFTsFlattened(
|
||||
metamaskState.allCollectibles,
|
||||
).length,
|
||||
[TRAITS.NUMBER_OF_TOKENS]: this._getNumberOfTokens(metamaskState),
|
||||
[TRAITS.OPENSEA_API_ENABLED]: metamaskState.openSeaEnabled,
|
||||
[TRAITS.THREE_BOX_ENABLED]: metamaskState.threeBoxSyncingAllowed,
|
||||
@ -603,22 +613,31 @@ export default class MetaMetricsController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all of the collectibles/NFTs the user
|
||||
* possesses across all networks and accounts.
|
||||
*
|
||||
* @param {object} metamaskState
|
||||
* @returns number of unique collectible addresses
|
||||
* @param {Object} allCollectibles
|
||||
* @returns {[]}
|
||||
*/
|
||||
_getNumberOfNFtCollection(metamaskState) {
|
||||
const { allCollectibles } = metamaskState;
|
||||
if (!allCollectibles) {
|
||||
return 0;
|
||||
}
|
||||
_getAllNFTsFlattened = memoize((allCollectibles = {}) => {
|
||||
return Object.values(allCollectibles)
|
||||
.flatMap((chainNFTs) => Object.values(chainNFTs))
|
||||
.flat();
|
||||
});
|
||||
|
||||
const allAddresses = Object.values(allCollectibles)
|
||||
.flatMap((chainCollectibles) => Object.values(chainCollectibles))
|
||||
.flat()
|
||||
.map((collectible) => collectible.address);
|
||||
const unique = [...new Set(allAddresses)];
|
||||
return unique.length;
|
||||
/**
|
||||
* Returns the number of unique collectible/NFT addresses the user
|
||||
* possesses across all networks and accounts.
|
||||
*
|
||||
* @param {Object} allCollectibles
|
||||
* @returns {number}
|
||||
*/
|
||||
_getAllUniqueNFTAddressesLength(allCollectibles = {}) {
|
||||
const allNFTAddresses = this._getAllNFTsFlattened(allCollectibles).map(
|
||||
(nft) => nft.address,
|
||||
);
|
||||
const uniqueAddresses = new Set(allNFTAddresses);
|
||||
return uniqueAddresses.size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -691,6 +691,7 @@ describe('MetaMetricsController', function () {
|
||||
[TRAITS.NFT_AUTODETECTION_ENABLED]: false,
|
||||
[TRAITS.NUMBER_OF_ACCOUNTS]: 2,
|
||||
[TRAITS.NUMBER_OF_NFT_COLLECTIONS]: 3,
|
||||
[TRAITS.NUMBER_OF_NFTS]: 4,
|
||||
[TRAITS.NUMBER_OF_TOKENS]: 5,
|
||||
[TRAITS.OPENSEA_API_ENABLED]: true,
|
||||
[TRAITS.THREE_BOX_ENABLED]: false,
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
MAINNET_CHAIN_ID,
|
||||
RINKEBY_CHAIN_ID,
|
||||
INFURA_BLOCKED_KEY,
|
||||
TEST_NETWORK_TICKER_MAP,
|
||||
} from '../../../../shared/constants/network';
|
||||
import { SECOND } from '../../../../shared/constants/time';
|
||||
import {
|
||||
@ -41,7 +42,11 @@ if (process.env.IN_TEST) {
|
||||
nickname: 'Localhost 8545',
|
||||
};
|
||||
} else if (process.env.METAMASK_DEBUG || env === 'test') {
|
||||
defaultProviderConfigOpts = { type: RINKEBY, chainId: RINKEBY_CHAIN_ID };
|
||||
defaultProviderConfigOpts = {
|
||||
type: RINKEBY,
|
||||
chainId: RINKEBY_CHAIN_ID,
|
||||
ticker: TEST_NETWORK_TICKER_MAP.rinkeby,
|
||||
};
|
||||
} else {
|
||||
defaultProviderConfigOpts = { type: MAINNET, chainId: MAINNET_CHAIN_ID };
|
||||
}
|
||||
@ -296,12 +301,12 @@ export default class NetworkController extends EventEmitter {
|
||||
INFURA_PROVIDER_TYPES.includes(type),
|
||||
`Unknown Infura provider type "${type}".`,
|
||||
);
|
||||
const { chainId } = NETWORK_TYPE_TO_ID_MAP[type];
|
||||
const { chainId, ticker } = NETWORK_TYPE_TO_ID_MAP[type];
|
||||
this.setProviderConfig({
|
||||
type,
|
||||
rpcUrl: '',
|
||||
chainId,
|
||||
ticker: 'ETH',
|
||||
ticker: ticker ?? 'ETH',
|
||||
nickname: '',
|
||||
});
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { ObservableStore } from '@metamask/obs-store';
|
||||
import stringify from 'fast-safe-stringify';
|
||||
import { CaveatTypes } from '../../../../shared/constants/permissions';
|
||||
import {
|
||||
LOG_IGNORE_METHODS,
|
||||
@ -158,9 +157,7 @@ export class PermissionLogController {
|
||||
? LOG_METHOD_TYPES.internal
|
||||
: LOG_METHOD_TYPES.restricted,
|
||||
origin: request.origin,
|
||||
request: stringify(request, null, 2),
|
||||
requestTime: Date.now(),
|
||||
response: null,
|
||||
responseTime: null,
|
||||
success: null,
|
||||
};
|
||||
@ -181,9 +178,12 @@ export class PermissionLogController {
|
||||
return;
|
||||
}
|
||||
|
||||
entry.response = stringify(response, null, 2);
|
||||
// The JSON-RPC 2.0 specification defines "success" by the presence of
|
||||
// either the "result" or "error" property. The specification forbids
|
||||
// both properties from being present simultaneously, and our JSON-RPC
|
||||
// stack is spec-compliant at the time of writing.
|
||||
entry.success = Object.hasOwnProperty.call(response, 'result');
|
||||
entry.responseTime = time;
|
||||
entry.success = !response.error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
import nanoid from 'nanoid';
|
||||
import { useFakeTimers } from 'sinon';
|
||||
import stringify from 'fast-safe-stringify';
|
||||
import { constants, getters, noop } from '../../../../test/mocks/permissions';
|
||||
import { PermissionLogController } from './permission-log';
|
||||
import { LOG_LIMIT, LOG_METHOD_TYPES } from './enums';
|
||||
@ -67,7 +66,7 @@ describe('PermissionLogController', () => {
|
||||
|
||||
req = RPC_REQUESTS.test_method(SUBJECTS.a.origin);
|
||||
req.id = REQUEST_IDS.a;
|
||||
res = { foo: 'bar' };
|
||||
res = { result: 'bar' };
|
||||
|
||||
logMiddleware({ ...req }, res);
|
||||
|
||||
@ -143,11 +142,17 @@ describe('PermissionLogController', () => {
|
||||
false,
|
||||
);
|
||||
|
||||
// validate final state
|
||||
// Validate final state
|
||||
expect(entry1).toStrictEqual(log[0]);
|
||||
expect(entry2).toStrictEqual(log[1]);
|
||||
expect(entry3).toStrictEqual(log[2]);
|
||||
expect(entry4).toStrictEqual(log[3]);
|
||||
|
||||
// Regression test: ensure "response" and "request" properties
|
||||
// are not present
|
||||
log.forEach((entry) =>
|
||||
expect('request' in entry && 'response' in entry).toBe(false),
|
||||
);
|
||||
});
|
||||
|
||||
it('handles responses added out of order', () => {
|
||||
@ -163,15 +168,15 @@ describe('PermissionLogController', () => {
|
||||
|
||||
// get make requests
|
||||
req.id = id1;
|
||||
const res1 = { foo: id1 };
|
||||
const res1 = { result: id1 };
|
||||
logMiddleware({ ...req }, { ...res1 }, getSavedMockNext(handlerArray));
|
||||
|
||||
req.id = id2;
|
||||
const res2 = { foo: id2 };
|
||||
const res2 = { result: id2 };
|
||||
logMiddleware({ ...req }, { ...res2 }, getSavedMockNext(handlerArray));
|
||||
|
||||
req.id = id3;
|
||||
const res3 = { foo: id3 };
|
||||
const res3 = { result: id3 };
|
||||
logMiddleware({ ...req }, { ...res3 }, getSavedMockNext(handlerArray));
|
||||
|
||||
// verify log state
|
||||
@ -181,10 +186,10 @@ describe('PermissionLogController', () => {
|
||||
const entry2 = log[1];
|
||||
const entry3 = log[2];
|
||||
|
||||
// all entries should be in correct order, without responses
|
||||
expect(entry1).toMatchObject({ id: id1, response: null });
|
||||
expect(entry2).toMatchObject({ id: id2, response: null });
|
||||
expect(entry3).toMatchObject({ id: id3, response: null });
|
||||
// all entries should be in correct order
|
||||
expect(entry1).toMatchObject({ id: id1, responseTime: null });
|
||||
expect(entry2).toMatchObject({ id: id2, responseTime: null });
|
||||
expect(entry3).toMatchObject({ id: id3, responseTime: null });
|
||||
|
||||
// call response handlers
|
||||
for (const i of [1, 2, 0]) {
|
||||
@ -226,7 +231,7 @@ describe('PermissionLogController', () => {
|
||||
it('handles a lack of response', () => {
|
||||
let req = RPC_REQUESTS.test_method(SUBJECTS.a.origin);
|
||||
req.id = REQUEST_IDS.a;
|
||||
let res = { foo: 'bar' };
|
||||
let res = { result: 'bar' };
|
||||
|
||||
// noop for next handler prevents recording of response
|
||||
logMiddleware({ ...req }, res, noop);
|
||||
@ -270,7 +275,7 @@ describe('PermissionLogController', () => {
|
||||
let log = permLog.getActivityLog();
|
||||
expect(log).toHaveLength(0);
|
||||
|
||||
const res = { foo: 'bar' };
|
||||
const res = { result: 'bar' };
|
||||
const req1 = RPC_REQUESTS.metamask_sendDomainMetadata(
|
||||
SUBJECTS.c.origin,
|
||||
'foobar',
|
||||
@ -288,7 +293,7 @@ describe('PermissionLogController', () => {
|
||||
|
||||
it('enforces log limit', () => {
|
||||
const req = RPC_REQUESTS.test_method(SUBJECTS.a.origin);
|
||||
const res = { foo: 'bar' };
|
||||
const res = { result: 'bar' };
|
||||
|
||||
// max out log
|
||||
let lastId;
|
||||
@ -647,19 +652,15 @@ function validateActivityEntry(entry, req, res, methodType, success) {
|
||||
expect(entry.method).toStrictEqual(req.method);
|
||||
expect(entry.origin).toStrictEqual(req.origin);
|
||||
expect(entry.methodType).toStrictEqual(methodType);
|
||||
expect(entry.request).toStrictEqual(stringify(req, null, 2));
|
||||
|
||||
expect(Number.isInteger(entry.requestTime)).toBe(true);
|
||||
if (res) {
|
||||
expect(Number.isInteger(entry.responseTime)).toBe(true);
|
||||
expect(entry.requestTime <= entry.responseTime).toBe(true);
|
||||
|
||||
expect(entry.success).toStrictEqual(success);
|
||||
expect(entry.response).toStrictEqual(stringify(res, null, 2));
|
||||
} else {
|
||||
expect(entry.requestTime > 0).toBe(true);
|
||||
expect(entry).toMatchObject({
|
||||
response: null,
|
||||
responseTime: null,
|
||||
success: null,
|
||||
});
|
||||
|
@ -68,7 +68,7 @@ export default class PreferencesController {
|
||||
ledgerTransportType: window.navigator.hid
|
||||
? LEDGER_TRANSPORT_TYPES.WEBHID
|
||||
: LEDGER_TRANSPORT_TYPES.U2F,
|
||||
theme: 'default',
|
||||
theme: 'light',
|
||||
...opts.initState,
|
||||
};
|
||||
|
||||
|
@ -353,14 +353,14 @@ describe('preferences controller', function () {
|
||||
});
|
||||
|
||||
describe('setTheme', function () {
|
||||
it('should default to value "default"', function () {
|
||||
it('should default to value "light"', function () {
|
||||
const state = preferencesController.store.getState();
|
||||
assert.equal(state.theme, 'default');
|
||||
assert.equal(state.theme, 'light');
|
||||
});
|
||||
|
||||
it('should set the setTheme property in state', function () {
|
||||
const state = preferencesController.store.getState();
|
||||
assert.equal(state.theme, 'default');
|
||||
assert.equal(state.theme, 'light');
|
||||
preferencesController.setTheme('dark');
|
||||
assert.equal(preferencesController.store.getState().theme, 'dark');
|
||||
});
|
||||
|
@ -39,6 +39,7 @@ import {
|
||||
PRIORITY_LEVELS,
|
||||
} from '../../../../shared/constants/gas';
|
||||
import { decGWEIToHexWEI } from '../../../../shared/modules/conversion.utils';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
HARDFORKS,
|
||||
MAINNET,
|
||||
@ -50,6 +51,7 @@ import {
|
||||
determineTransactionType,
|
||||
isEIP1559Transaction,
|
||||
} from '../../../../shared/modules/transaction.utils';
|
||||
import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
|
||||
import TransactionStateManager from './tx-state-manager';
|
||||
import TxGasUtil from './tx-gas-utils';
|
||||
import PendingTransactionTracker from './pending-tx-tracker';
|
||||
@ -62,6 +64,15 @@ const SWAP_TRANSACTION_TYPES = [
|
||||
TRANSACTION_TYPES.SWAP_APPROVAL,
|
||||
];
|
||||
|
||||
// Only certain types of transactions should be allowed to be specified when
|
||||
// adding a new unapproved transaction.
|
||||
const VALID_UNAPPROVED_TRANSACTION_TYPES = [
|
||||
...SWAP_TRANSACTION_TYPES,
|
||||
TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
|
||||
];
|
||||
|
||||
/**
|
||||
* @typedef {import('../../../../shared/constants/transaction').TransactionMeta} TransactionMeta
|
||||
* @typedef {import('../../../../shared/constants/transaction').TransactionMetaMetricsEventString} TransactionMetaMetricsEventString
|
||||
@ -650,7 +661,7 @@ export default class TransactionController extends EventEmitter {
|
||||
async addUnapprovedTransaction(txParams, origin, transactionType) {
|
||||
if (
|
||||
transactionType !== undefined &&
|
||||
!SWAP_TRANSACTION_TYPES.includes(transactionType)
|
||||
!VALID_UNAPPROVED_TRANSACTION_TYPES.includes(transactionType)
|
||||
) {
|
||||
throw new Error(
|
||||
`TransactionController - invalid transactionType value: ${transactionType}`,
|
||||
@ -674,7 +685,7 @@ export default class TransactionController extends EventEmitter {
|
||||
origin,
|
||||
});
|
||||
|
||||
if (origin === 'metamask') {
|
||||
if (origin === ORIGIN_METAMASK) {
|
||||
// Assert the from address is the selected address
|
||||
if (normalizedTxParams.from !== this.getSelectedAddress()) {
|
||||
throw ethErrors.rpc.internal({
|
||||
@ -783,7 +794,7 @@ export default class TransactionController extends EventEmitter {
|
||||
// then we set maxFeePerGas and maxPriorityFeePerGas to the suggested gasPrice.
|
||||
txMeta.txParams.maxFeePerGas = txMeta.txParams.gasPrice;
|
||||
txMeta.txParams.maxPriorityFeePerGas = txMeta.txParams.gasPrice;
|
||||
if (eip1559V2Enabled && txMeta.origin !== 'metamask') {
|
||||
if (eip1559V2Enabled && txMeta.origin !== ORIGIN_METAMASK) {
|
||||
txMeta.userFeeLevel = PRIORITY_LEVELS.DAPP_SUGGESTED;
|
||||
} else {
|
||||
txMeta.userFeeLevel = CUSTOM_GAS_ESTIMATE;
|
||||
@ -794,7 +805,7 @@ export default class TransactionController extends EventEmitter {
|
||||
defaultMaxPriorityFeePerGas &&
|
||||
!txMeta.txParams.maxFeePerGas &&
|
||||
!txMeta.txParams.maxPriorityFeePerGas) ||
|
||||
txMeta.origin === 'metamask'
|
||||
txMeta.origin === ORIGIN_METAMASK
|
||||
) {
|
||||
txMeta.userFeeLevel = GAS_RECOMMENDATIONS.MEDIUM;
|
||||
} else if (eip1559V2Enabled) {
|
||||
@ -1779,7 +1790,10 @@ export default class TransactionController extends EventEmitter {
|
||||
txMeta,
|
||||
'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce',
|
||||
);
|
||||
this._dropTransaction(otherTxMeta.id);
|
||||
// Drop any transaction that wasn't previously failed (off chain failure)
|
||||
if (otherTxMeta.status !== TRANSACTION_STATUSES.FAILED) {
|
||||
this._dropTransaction(otherTxMeta.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1833,7 +1847,7 @@ export default class TransactionController extends EventEmitter {
|
||||
this._trackMetaMetricsEvent({
|
||||
event: 'Swap Failed',
|
||||
sensitiveProperties: { ...txMeta.swapMetaData },
|
||||
category: 'swaps',
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
});
|
||||
} else {
|
||||
const tokensReceived = getSwapsTokensReceivedFromTxMeta(
|
||||
@ -1863,7 +1877,7 @@ export default class TransactionController extends EventEmitter {
|
||||
|
||||
this._trackMetaMetricsEvent({
|
||||
event: 'Swap Completed',
|
||||
category: 'swaps',
|
||||
category: EVENT.CATEGORIES.SWAPS,
|
||||
sensitiveProperties: {
|
||||
...txMeta.swapMetaData,
|
||||
token_to_amount_received: tokensReceived,
|
||||
@ -1893,7 +1907,7 @@ export default class TransactionController extends EventEmitter {
|
||||
defaultGasEstimates,
|
||||
metamaskNetworkId: network,
|
||||
} = txMeta;
|
||||
const source = referrer === 'metamask' ? 'user' : 'dapp';
|
||||
const source = referrer === ORIGIN_METAMASK ? 'user' : 'dapp';
|
||||
|
||||
const { assetType, tokenStandard } = await determineTransactionAssetType(
|
||||
txMeta,
|
||||
@ -2036,7 +2050,7 @@ export default class TransactionController extends EventEmitter {
|
||||
// occur.
|
||||
case TRANSACTION_EVENTS.ADDED:
|
||||
this.createEventFragment({
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
initialEvent: TRANSACTION_EVENTS.ADDED,
|
||||
successEvent: TRANSACTION_EVENTS.APPROVED,
|
||||
failureEvent: TRANSACTION_EVENTS.REJECTED,
|
||||
@ -2057,7 +2071,7 @@ export default class TransactionController extends EventEmitter {
|
||||
case TRANSACTION_EVENTS.APPROVED:
|
||||
case TRANSACTION_EVENTS.REJECTED:
|
||||
this.createEventFragment({
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
successEvent: TRANSACTION_EVENTS.APPROVED,
|
||||
failureEvent: TRANSACTION_EVENTS.REJECTED,
|
||||
properties,
|
||||
@ -2078,7 +2092,7 @@ export default class TransactionController extends EventEmitter {
|
||||
// properties to the transaction event.
|
||||
case TRANSACTION_EVENTS.SUBMITTED:
|
||||
this.createEventFragment({
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
initialEvent: TRANSACTION_EVENTS.SUBMITTED,
|
||||
successEvent: TRANSACTION_EVENTS.FINALIZED,
|
||||
properties,
|
||||
@ -2097,7 +2111,7 @@ export default class TransactionController extends EventEmitter {
|
||||
// fragment does not exist.
|
||||
case TRANSACTION_EVENTS.FINALIZED:
|
||||
this.createEventFragment({
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
successEvent: TRANSACTION_EVENTS.FINALIZED,
|
||||
properties,
|
||||
sensitiveProperties,
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
getTestAccounts,
|
||||
} from '../../../../test/stub/provider';
|
||||
import mockEstimates from '../../../../test/data/mock-estimates.json';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
TRANSACTION_STATUSES,
|
||||
TRANSACTION_TYPES,
|
||||
@ -26,6 +27,7 @@ import {
|
||||
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 '.';
|
||||
|
||||
const noop = () => true;
|
||||
@ -791,7 +793,7 @@ describe('Transaction Controller', function () {
|
||||
},
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
|
||||
origin: 'metamask',
|
||||
origin: ORIGIN_METAMASK,
|
||||
chainId: currentChainId,
|
||||
time: 1624408066355,
|
||||
metamaskNetworkId: currentNetworkId,
|
||||
@ -1442,7 +1444,7 @@ describe('Transaction Controller', function () {
|
||||
nonce: '0x4b',
|
||||
},
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
origin: 'metamask',
|
||||
origin: ORIGIN_METAMASK,
|
||||
chainId: currentChainId,
|
||||
time: 1624408066355,
|
||||
metamaskNetworkId: currentNetworkId,
|
||||
@ -1459,7 +1461,7 @@ describe('Transaction Controller', function () {
|
||||
successEvent: 'Transaction Approved',
|
||||
failureEvent: 'Transaction Rejected',
|
||||
uniqueIdentifier: 'transaction-added-1',
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
persist: true,
|
||||
properties: {
|
||||
chain_id: '0x2a',
|
||||
@ -1467,7 +1469,7 @@ describe('Transaction Controller', function () {
|
||||
gas_edit_attempted: 'none',
|
||||
gas_edit_type: 'none',
|
||||
network: '42',
|
||||
referrer: 'metamask',
|
||||
referrer: ORIGIN_METAMASK,
|
||||
source: 'user',
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
account_type: 'MetaMask',
|
||||
@ -1538,7 +1540,7 @@ describe('Transaction Controller', function () {
|
||||
initialEvent: 'Transaction Submitted',
|
||||
successEvent: 'Transaction Finalized',
|
||||
uniqueIdentifier: 'transaction-submitted-1',
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
persist: true,
|
||||
properties: {
|
||||
chain_id: '0x2a',
|
||||
@ -1546,7 +1548,7 @@ describe('Transaction Controller', function () {
|
||||
gas_edit_attempted: 'none',
|
||||
gas_edit_type: 'none',
|
||||
network: '42',
|
||||
referrer: 'metamask',
|
||||
referrer: ORIGIN_METAMASK,
|
||||
source: 'user',
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
account_type: 'MetaMask',
|
||||
@ -1627,7 +1629,7 @@ describe('Transaction Controller', function () {
|
||||
successEvent: 'Transaction Approved',
|
||||
failureEvent: 'Transaction Rejected',
|
||||
uniqueIdentifier: 'transaction-added-1',
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
persist: true,
|
||||
properties: {
|
||||
chain_id: '0x2a',
|
||||
@ -1708,7 +1710,7 @@ describe('Transaction Controller', function () {
|
||||
initialEvent: 'Transaction Submitted',
|
||||
successEvent: 'Transaction Finalized',
|
||||
uniqueIdentifier: 'transaction-submitted-1',
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
persist: true,
|
||||
properties: {
|
||||
chain_id: '0x2a',
|
||||
@ -1789,7 +1791,7 @@ describe('Transaction Controller', function () {
|
||||
successEvent: 'Transaction Approved',
|
||||
failureEvent: 'Transaction Rejected',
|
||||
uniqueIdentifier: 'transaction-added-1',
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
persist: true,
|
||||
properties: {
|
||||
chain_id: '0x2a',
|
||||
@ -1853,7 +1855,7 @@ describe('Transaction Controller', function () {
|
||||
failureEvent: 'Transaction Rejected',
|
||||
uniqueIdentifier: 'transaction-added-1',
|
||||
persist: true,
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
properties: {
|
||||
network: '42',
|
||||
referrer: 'other',
|
||||
@ -1926,7 +1928,7 @@ describe('Transaction Controller', function () {
|
||||
failureEvent: 'Transaction Rejected',
|
||||
uniqueIdentifier: 'transaction-added-1',
|
||||
persist: true,
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
properties: {
|
||||
chain_id: '0x2a',
|
||||
eip_1559_version: '1',
|
||||
|
@ -6,6 +6,7 @@ import createId from '../../../../shared/modules/random-id';
|
||||
import { TRANSACTION_STATUSES } from '../../../../shared/constants/transaction';
|
||||
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
||||
import { transactionMatchesNetwork } from '../../../../shared/modules/transaction.utils';
|
||||
import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
|
||||
import {
|
||||
generateHistoryEntry,
|
||||
replayHistory,
|
||||
@ -92,7 +93,7 @@ export default class TransactionStateManager extends EventEmitter {
|
||||
if (
|
||||
opts.txParams &&
|
||||
typeof opts.origin === 'string' &&
|
||||
opts.origin !== 'metamask'
|
||||
opts.origin !== ORIGIN_METAMASK
|
||||
) {
|
||||
if (typeof opts.txParams.gasPrice !== 'undefined') {
|
||||
dappSuggestedGasFees = {
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
KOVAN_NETWORK_ID,
|
||||
} from '../../../../shared/constants/network';
|
||||
import { GAS_LIMITS } from '../../../../shared/constants/gas';
|
||||
import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
|
||||
import TxStateManager from './tx-state-manager';
|
||||
import { snapshotFromTxMeta } from './lib/tx-state-history-helpers';
|
||||
|
||||
@ -1188,7 +1189,7 @@ describe('TransactionStateManager', function () {
|
||||
};
|
||||
const generatedTransaction = txStateManager.generateTxMeta({
|
||||
txParams,
|
||||
origin: 'metamask',
|
||||
origin: ORIGIN_METAMASK,
|
||||
});
|
||||
assert.ok(generatedTransaction);
|
||||
assert.strictEqual(generatedTransaction.dappSuggestedGasFees, null);
|
||||
|
55
app/scripts/detect-multiple-instances.js
Normal file
55
app/scripts/detect-multiple-instances.js
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Sets up two-way communication between the
|
||||
* mainline version of extension and Flask build
|
||||
* in order to detect & warn if there are two different
|
||||
* versions running simultaneously.
|
||||
*/
|
||||
|
||||
import browser from 'webextension-polyfill';
|
||||
import {
|
||||
PLATFORM_CHROME,
|
||||
PLATFORM_FIREFOX,
|
||||
CHROME_BUILD_IDS,
|
||||
FIREFOX_BUILD_IDS,
|
||||
} from '../../shared/constants/app';
|
||||
import { getPlatform } from './lib/util';
|
||||
|
||||
const MESSAGE_TEXT = 'isRunning';
|
||||
|
||||
const showWarning = () =>
|
||||
console.warn('Warning! You have multiple instances of MetaMask running!');
|
||||
|
||||
/**
|
||||
* Handles the ping message sent from other extension.
|
||||
* Displays console warning if it's active.
|
||||
*
|
||||
* @param message - The message received from the other extension
|
||||
*/
|
||||
export const onMessageReceived = (message) => {
|
||||
if (message === MESSAGE_TEXT) {
|
||||
showWarning();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends the ping message sent to other extensions to detect whether it's active or not.
|
||||
*/
|
||||
export const checkForMultipleVersionsRunning = async () => {
|
||||
if (getPlatform() !== PLATFORM_CHROME && getPlatform() !== PLATFORM_FIREFOX) {
|
||||
return;
|
||||
}
|
||||
const buildIds =
|
||||
getPlatform() === PLATFORM_CHROME ? CHROME_BUILD_IDS : FIREFOX_BUILD_IDS;
|
||||
|
||||
const thisBuild = browser.runtime.id;
|
||||
|
||||
for (const id of buildIds) {
|
||||
if (id !== thisBuild) {
|
||||
try {
|
||||
await browser.runtime.sendMessage(id, MESSAGE_TEXT);
|
||||
} catch (error) {
|
||||
// Should do nothing if receiving end was not reached (no other instances running)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
104
app/scripts/detect-multiple-instances.test.js
Normal file
104
app/scripts/detect-multiple-instances.test.js
Normal file
@ -0,0 +1,104 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import browser from 'webextension-polyfill';
|
||||
import sinon from 'sinon';
|
||||
import {
|
||||
PLATFORM_CHROME,
|
||||
PLATFORM_EDGE,
|
||||
METAMASK_BETA_CHROME_ID,
|
||||
METAMASK_PROD_CHROME_ID,
|
||||
METAMASK_FLASK_CHROME_ID,
|
||||
} from '../../shared/constants/app';
|
||||
import {
|
||||
checkForMultipleVersionsRunning,
|
||||
onMessageReceived,
|
||||
} from './detect-multiple-instances';
|
||||
import * as util from './lib/util';
|
||||
|
||||
describe('multiple instances running detector', function () {
|
||||
const PING_MESSAGE = 'isRunning';
|
||||
|
||||
let sendMessageStub = sinon.stub();
|
||||
|
||||
beforeEach(async function () {
|
||||
sinon.replace(browser, 'runtime', {
|
||||
sendMessage: sendMessageStub,
|
||||
id: METAMASK_BETA_CHROME_ID,
|
||||
});
|
||||
|
||||
sinon.stub(util, 'getPlatform').callsFake((_) => {
|
||||
return PLATFORM_CHROME;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('checkForMultipleVersionsRunning', function () {
|
||||
it('should send ping message to multiple instances', async function () {
|
||||
await checkForMultipleVersionsRunning();
|
||||
|
||||
assert(sendMessageStub.calledTwice);
|
||||
assert(
|
||||
sendMessageStub
|
||||
.getCall(0)
|
||||
.calledWithExactly(METAMASK_PROD_CHROME_ID, PING_MESSAGE),
|
||||
);
|
||||
assert(
|
||||
sendMessageStub
|
||||
.getCall(1)
|
||||
.calledWithExactly(METAMASK_FLASK_CHROME_ID, PING_MESSAGE),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not send ping message if platform is not Chrome or Firefox', async function () {
|
||||
util.getPlatform.restore();
|
||||
sendMessageStub = sinon.stub();
|
||||
|
||||
sinon.stub(util, 'getPlatform').callsFake((_) => {
|
||||
return PLATFORM_EDGE;
|
||||
});
|
||||
|
||||
await checkForMultipleVersionsRunning();
|
||||
|
||||
assert(sendMessageStub.notCalled);
|
||||
});
|
||||
|
||||
it('should not expose an error outside if sendMessage throws', async function () {
|
||||
sinon.restore();
|
||||
|
||||
sinon.replace(browser, 'runtime', {
|
||||
sendMessage: sinon.stub().throws(),
|
||||
id: METAMASK_BETA_CHROME_ID,
|
||||
});
|
||||
|
||||
const spy = sinon.spy(checkForMultipleVersionsRunning);
|
||||
|
||||
await checkForMultipleVersionsRunning();
|
||||
|
||||
assert(!spy.threw());
|
||||
});
|
||||
});
|
||||
|
||||
describe('onMessageReceived', function () {
|
||||
beforeEach(function () {
|
||||
sinon.spy(console, 'warn');
|
||||
});
|
||||
|
||||
it('should print warning message to on ping message received', async function () {
|
||||
onMessageReceived(PING_MESSAGE);
|
||||
|
||||
assert(
|
||||
console.warn.calledWithExactly(
|
||||
'Warning! You have multiple instances of MetaMask running!',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('should not print warning message if wrong message received', async function () {
|
||||
onMessageReceived(PING_MESSAGE.concat('wrong'));
|
||||
|
||||
assert(console.warn.notCalled);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import { EVENT_NAMES } from '../../../shared/constants/metametrics';
|
||||
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
|
||||
import { SECOND } from '../../../shared/constants/time';
|
||||
|
||||
const USER_PROMPTED_EVENT_NAME_MAP = {
|
||||
@ -46,7 +46,7 @@ export default function createRPCMethodTrackingMiddleware({
|
||||
const userRejected = res.error?.code === 4001;
|
||||
trackEvent({
|
||||
event: USER_PROMPTED_EVENT_NAME_MAP[req.method],
|
||||
category: 'inpage_provider',
|
||||
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
|
||||
referrer: {
|
||||
url: origin,
|
||||
},
|
||||
@ -62,7 +62,7 @@ export default function createRPCMethodTrackingMiddleware({
|
||||
} else if (typeof samplingTimeouts[req.method] === 'undefined') {
|
||||
trackEvent({
|
||||
event: 'Provider Method Called',
|
||||
category: 'inpage_provider',
|
||||
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
|
||||
referrer: {
|
||||
url: origin,
|
||||
},
|
||||
|
@ -4,6 +4,7 @@ import { bufferToHex, stripHexPrefix } from 'ethereumjs-util';
|
||||
import { ethErrors } from 'eth-rpc-errors';
|
||||
import log from 'loglevel';
|
||||
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||
import { EVENT } from '../../../shared/constants/metametrics';
|
||||
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
|
||||
import createId from '../../../shared/modules/random-id';
|
||||
import { addHexPrefix } from './util';
|
||||
@ -227,7 +228,7 @@ export default class DecryptMessageManager extends EventEmitter {
|
||||
if (reason) {
|
||||
this.metricsEvent({
|
||||
event: reason,
|
||||
category: 'Messages',
|
||||
category: EVENT.CATEGORIES.MESSAGES,
|
||||
properties: {
|
||||
action: 'Decrypt Message Request',
|
||||
},
|
||||
|
@ -3,6 +3,7 @@ import { ObservableStore } from '@metamask/obs-store';
|
||||
import { ethErrors } from 'eth-rpc-errors';
|
||||
import log from 'loglevel';
|
||||
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||
import { EVENT } from '../../../shared/constants/metametrics';
|
||||
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
|
||||
import createId from '../../../shared/modules/random-id';
|
||||
|
||||
@ -216,7 +217,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
|
||||
if (reason) {
|
||||
this.metricsEvent({
|
||||
event: reason,
|
||||
category: 'Messages',
|
||||
category: EVENT.CATEGORIES.MESSAGES,
|
||||
properties: {
|
||||
action: 'Encryption public key Request',
|
||||
},
|
||||
|
@ -5,6 +5,7 @@ import { ethErrors } from 'eth-rpc-errors';
|
||||
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
|
||||
import createId from '../../../shared/modules/random-id';
|
||||
import { EVENT } from '../../../shared/constants/metametrics';
|
||||
|
||||
/**
|
||||
* Represents, and contains data about, an 'eth_sign' type signature request. These are created when a signature for
|
||||
@ -211,7 +212,7 @@ export default class MessageManager extends EventEmitter {
|
||||
const msg = this.getMsg(msgId);
|
||||
this.metricsEvent({
|
||||
event: reason,
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
properties: {
|
||||
action: 'Sign Request',
|
||||
type: msg.type,
|
||||
|
@ -6,6 +6,7 @@ import log from 'loglevel';
|
||||
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
|
||||
import createId from '../../../shared/modules/random-id';
|
||||
import { EVENT } from '../../../shared/constants/metametrics';
|
||||
import { addHexPrefix } from './util';
|
||||
|
||||
const hexRe = /^[0-9A-Fa-f]+$/gu;
|
||||
@ -231,7 +232,7 @@ export default class PersonalMessageManager extends EventEmitter {
|
||||
const msg = this.getMsg(msgId);
|
||||
this.metricsEvent({
|
||||
event: reason,
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
properties: {
|
||||
action: 'Sign Request',
|
||||
type: msg.type,
|
||||
|
@ -2,6 +2,7 @@ import { ethErrors, errorCodes } from 'eth-rpc-errors';
|
||||
import validUrl from 'valid-url';
|
||||
import { omit } from 'lodash';
|
||||
import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
import {
|
||||
isPrefixedFormattedHexString,
|
||||
isSafeChainId,
|
||||
@ -249,7 +250,7 @@ async function addEthereumChainHandler(
|
||||
|
||||
sendMetrics({
|
||||
event: 'Custom Network Added',
|
||||
category: 'Network',
|
||||
category: EVENT.CATEGORIES.NETWORK,
|
||||
referrer: {
|
||||
url: origin,
|
||||
},
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
|
||||
/**
|
||||
* This RPC method is called by the inpage provider whenever it detects the
|
||||
@ -48,7 +49,7 @@ function logWeb3ShimUsageHandler(
|
||||
sendMetrics(
|
||||
{
|
||||
event: `Website Accessed window.web3 Shim`,
|
||||
category: 'inpage_provider',
|
||||
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
|
||||
referrer: {
|
||||
url: origin,
|
||||
},
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { ethErrors } from 'eth-rpc-errors';
|
||||
import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
|
||||
|
||||
const watchAsset = {
|
||||
@ -36,9 +37,14 @@ async function watchAssetHandler(
|
||||
) {
|
||||
try {
|
||||
const { options: asset, type } = req.params;
|
||||
res.result = await handleWatchAssetRequest(asset, type);
|
||||
const handleWatchAssetResult = await handleWatchAssetRequest(asset, type);
|
||||
await handleWatchAssetResult.result;
|
||||
res.result = true;
|
||||
return end();
|
||||
} catch (error) {
|
||||
if (error.message === 'User rejected to watch the asset.') {
|
||||
return end(ethErrors.provider.userRejectedRequest());
|
||||
}
|
||||
return end(error);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import jsonschema from 'jsonschema';
|
||||
import { MESSAGE_TYPE } from '../../../shared/constants/app';
|
||||
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
|
||||
import createId from '../../../shared/modules/random-id';
|
||||
import { EVENT } from '../../../shared/constants/metametrics';
|
||||
import { isValidHexAddress } from '../../../shared/modules/hexstring-utils';
|
||||
|
||||
/**
|
||||
@ -303,7 +304,7 @@ export default class TypedMessageManager extends EventEmitter {
|
||||
const msg = this.getMsg(msgId);
|
||||
this.metricsEvent({
|
||||
event: reason,
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
properties: {
|
||||
action: 'Sign Request',
|
||||
version: msg.msgParams.version,
|
||||
|
@ -30,7 +30,7 @@ import {
|
||||
ControllerMessenger,
|
||||
CurrencyRateController,
|
||||
PhishingController,
|
||||
NotificationController,
|
||||
AnnouncementController,
|
||||
GasFeeController,
|
||||
TokenListController,
|
||||
TokensController,
|
||||
@ -75,17 +75,23 @@ import { UI_NOTIFICATIONS } from '../../shared/notifications';
|
||||
import { toChecksumHexAddress } from '../../shared/modules/hexstring-utils';
|
||||
import { MILLISECOND } from '../../shared/constants/time';
|
||||
import {
|
||||
ORIGIN_METAMASK,
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
MESSAGE_TYPE,
|
||||
///: END:ONLY_INCLUDE_IN
|
||||
POLLING_TOKEN_ENVIRONMENT_TYPES,
|
||||
SUBJECT_TYPES,
|
||||
} from '../../shared/constants/app';
|
||||
import { EVENT } from '../../shared/constants/metametrics';
|
||||
|
||||
import { hexToDecimal } from '../../ui/helpers/utils/conversions.util';
|
||||
import { getTokenValueParam } from '../../ui/helpers/utils/token-util';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
import { parseStandardTokenTransactionData } from '../../shared/modules/transaction.utils';
|
||||
import {
|
||||
onMessageReceived,
|
||||
checkForMultipleVersionsRunning,
|
||||
} from './detect-multiple-instances';
|
||||
import ComposableObservableStore from './lib/ComposableObservableStore';
|
||||
import AccountTracker from './lib/account-tracker';
|
||||
import createLoggerMiddleware from './lib/createLoggerMiddleware';
|
||||
@ -396,7 +402,10 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.currencyRateController = new CurrencyRateController({
|
||||
includeUSDRate: true,
|
||||
messenger: currencyRateMessenger,
|
||||
state: initState.CurrencyController,
|
||||
state: {
|
||||
...initState.CurrencyController,
|
||||
nativeCurrency: this.networkController.providerStore.getState().ticker,
|
||||
},
|
||||
});
|
||||
|
||||
const tokenListMessenger = this.controllerMessenger.getRestricted({
|
||||
@ -449,9 +458,9 @@ export default class MetamaskController extends EventEmitter {
|
||||
|
||||
this.phishingController = new PhishingController();
|
||||
|
||||
this.notificationController = new NotificationController(
|
||||
{ allNotifications: UI_NOTIFICATIONS },
|
||||
initState.NotificationController,
|
||||
this.announcementController = new AnnouncementController(
|
||||
{ allAnnouncements: UI_NOTIFICATIONS },
|
||||
initState.AnnouncementController,
|
||||
);
|
||||
|
||||
// token exchange rate tracker
|
||||
@ -628,7 +637,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.workerController = new IframeExecutionService({
|
||||
onError: this.onExecutionEnvironmentError.bind(this),
|
||||
iframeUrl: new URL(
|
||||
'https://metamask.github.io/iframe-execution-environment/0.4.3',
|
||||
'https://metamask.github.io/iframe-execution-environment/0.4.4',
|
||||
),
|
||||
messenger: this.controllerMessenger.getRestricted({
|
||||
name: 'ExecutionService',
|
||||
@ -649,6 +658,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
`${this.permissionController.name}:hasPermissions`,
|
||||
`${this.permissionController.name}:requestPermissions`,
|
||||
`${this.permissionController.name}:revokeAllPermissions`,
|
||||
`${this.permissionController.name}:revokePermissionForAllSubjects`,
|
||||
],
|
||||
});
|
||||
|
||||
@ -848,7 +858,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.metaMetricsController.trackEvent(
|
||||
{
|
||||
event: 'Tx Status Update: On-Chain Failure',
|
||||
category: 'Background',
|
||||
category: EVENT.CATEGORIES.BACKGROUND,
|
||||
properties: {
|
||||
action: 'Transactions',
|
||||
errorMessage: txMeta.simulationFails?.reason,
|
||||
@ -979,7 +989,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
PermissionLogController: this.permissionLogController.store,
|
||||
SubjectMetadataController: this.subjectMetadataController,
|
||||
ThreeBoxController: this.threeBoxController.store,
|
||||
NotificationController: this.notificationController,
|
||||
AnnouncementController: this.announcementController,
|
||||
GasFeeController: this.gasFeeController,
|
||||
TokenListController: this.tokenListController,
|
||||
TokensController: this.tokensController,
|
||||
@ -1019,7 +1029,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
SwapsController: this.swapsController.store,
|
||||
EnsController: this.ensController.store,
|
||||
ApprovalController: this.approvalController,
|
||||
NotificationController: this.notificationController,
|
||||
AnnouncementController: this.announcementController,
|
||||
GasFeeController: this.gasFeeController,
|
||||
TokenListController: this.tokenListController,
|
||||
TokensController: this.tokensController,
|
||||
@ -1057,6 +1067,11 @@ export default class MetamaskController extends EventEmitter {
|
||||
|
||||
// TODO:LegacyProvider: Delete
|
||||
this.publicConfigStore = this.createPublicConfigStore();
|
||||
|
||||
// Multiple MetaMask instances launched warning
|
||||
this.extension.runtime.onMessageExternal.addListener(onMessageReceived);
|
||||
// Fire a ping message to check if other extensions are running
|
||||
checkForMultipleVersionsRunning();
|
||||
}
|
||||
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
@ -1071,13 +1086,14 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.controllerMessenger,
|
||||
'SnapController:add',
|
||||
),
|
||||
clearSnapState: (fromSubject) =>
|
||||
this.controllerMessenger.call(
|
||||
'SnapController:updateSnapState',
|
||||
fromSubject,
|
||||
null,
|
||||
),
|
||||
clearSnapState: this.controllerMessenger.call.bind(
|
||||
this.controllerMessenger,
|
||||
'SnapController:clearSnapState',
|
||||
),
|
||||
getMnemonic: this.getPrimaryKeyringMnemonic.bind(this),
|
||||
getUnlockPromise: this.appStateController.getUnlockPromise.bind(
|
||||
this.appStateController,
|
||||
),
|
||||
getSnap: this.controllerMessenger.call.bind(
|
||||
this.controllerMessenger,
|
||||
'SnapController:get',
|
||||
@ -1201,7 +1217,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
(snapId) => {
|
||||
this.metaMetricsController.trackEvent({
|
||||
event: 'Snap Installed',
|
||||
category: 'Snaps',
|
||||
category: EVENT.CATEGORIES.SNAPS,
|
||||
properties: {
|
||||
snap_id: snapId,
|
||||
},
|
||||
@ -1224,7 +1240,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
version,
|
||||
// account mgmt
|
||||
getAccounts: async ({ origin }) => {
|
||||
if (origin === 'metamask') {
|
||||
if (origin === ORIGIN_METAMASK) {
|
||||
const selectedAddress = this.preferencesController.getSelectedAddress();
|
||||
return selectedAddress ? [selectedAddress] : [];
|
||||
} else if (this.isUnlocked()) {
|
||||
@ -1364,7 +1380,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
keyringController,
|
||||
metaMetricsController,
|
||||
networkController,
|
||||
notificationController,
|
||||
announcementController,
|
||||
onboardingController,
|
||||
permissionController,
|
||||
preferencesController,
|
||||
@ -1819,8 +1835,8 @@ export default class MetamaskController extends EventEmitter {
|
||||
},
|
||||
|
||||
// Notifications
|
||||
updateViewedNotifications: notificationController.updateViewed.bind(
|
||||
notificationController,
|
||||
updateViewedNotifications: announcementController.updateViewed.bind(
|
||||
announcementController,
|
||||
),
|
||||
|
||||
// GasFeeController
|
||||
@ -3270,7 +3286,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
setupProviderConnection(outStream, sender, subjectType) {
|
||||
let origin;
|
||||
if (subjectType === SUBJECT_TYPES.INTERNAL) {
|
||||
origin = 'metamask';
|
||||
origin = ORIGIN_METAMASK;
|
||||
}
|
||||
///: BEGIN:ONLY_INCLUDE_IN(flask)
|
||||
else if (subjectType === SUBJECT_TYPES.SNAP) {
|
||||
@ -3513,6 +3529,10 @@ export default class MetamaskController extends EventEmitter {
|
||||
|
||||
return Object.values(approvedPermissions);
|
||||
},
|
||||
getPermissions: this.permissionController.getPermissions.bind(
|
||||
this.permissionController,
|
||||
origin,
|
||||
),
|
||||
getAccounts: this.getPermittedAccounts.bind(this, origin),
|
||||
installSnaps: this.snapController.installSnaps.bind(
|
||||
this.snapController,
|
||||
@ -3572,7 +3592,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
* @returns {string} The connection's id (so that it can be deleted later)
|
||||
*/
|
||||
addConnection(origin, { engine }) {
|
||||
if (origin === 'metamask') {
|
||||
if (origin === ORIGIN_METAMASK) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { pubToAddress, bufferToHex } from 'ethereumjs-util';
|
||||
import { obj as createThoughStream } from 'through2';
|
||||
import EthQuery from 'eth-query';
|
||||
import proxyquire from 'proxyquire';
|
||||
import browser from 'webextension-polyfill';
|
||||
import { TRANSACTION_STATUSES } from '../../shared/constants/transaction';
|
||||
import createTxMeta from '../../test/lib/createTxMeta';
|
||||
import { NETWORK_TYPE_RPC } from '../../shared/constants/network';
|
||||
@ -71,6 +72,9 @@ const browserPolyfillMock = {
|
||||
onInstalled: {
|
||||
addListener: () => undefined,
|
||||
},
|
||||
onMessageExternal: {
|
||||
addListener: () => undefined,
|
||||
},
|
||||
getPlatformInfo: async () => 'mac',
|
||||
},
|
||||
};
|
||||
@ -131,6 +135,10 @@ describe('MetaMaskController', function () {
|
||||
.get(/.*/u)
|
||||
.reply(200, '{"JPY":12415.9}');
|
||||
|
||||
sandbox.replace(browser, 'runtime', {
|
||||
sendMessage: sandbox.stub().rejects(),
|
||||
});
|
||||
|
||||
metamaskController = new MetaMaskController({
|
||||
showUserConfirmation: noop,
|
||||
encryptor: {
|
||||
|
40
app/scripts/migrations/070.js
Normal file
40
app/scripts/migrations/070.js
Normal file
@ -0,0 +1,40 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
const version = 70;
|
||||
|
||||
/**
|
||||
* Removes the `request` and `response` properties from
|
||||
* `PermissionLogController.permissionActivityLog` objects.
|
||||
*/
|
||||
export default {
|
||||
version,
|
||||
async migrate(originalVersionedData) {
|
||||
const versionedData = cloneDeep(originalVersionedData);
|
||||
versionedData.meta.version = version;
|
||||
const state = versionedData.data;
|
||||
const newState = transformState(state);
|
||||
versionedData.data = newState;
|
||||
return versionedData;
|
||||
},
|
||||
};
|
||||
|
||||
function transformState(state) {
|
||||
if (Array.isArray(state?.PermissionLogController?.permissionActivityLog)) {
|
||||
const {
|
||||
PermissionLogController: { permissionActivityLog },
|
||||
} = state;
|
||||
|
||||
// mutate activity log entries in place
|
||||
permissionActivityLog.forEach((logEntry) => {
|
||||
if (
|
||||
logEntry &&
|
||||
typeof logEntry === 'object' &&
|
||||
!Array.isArray(logEntry)
|
||||
) {
|
||||
delete logEntry.request;
|
||||
delete logEntry.response;
|
||||
}
|
||||
});
|
||||
}
|
||||
return state;
|
||||
}
|
273
app/scripts/migrations/070.test.js
Normal file
273
app/scripts/migrations/070.test.js
Normal file
@ -0,0 +1,273 @@
|
||||
import migration70 from './070';
|
||||
|
||||
describe('migration #70', () => {
|
||||
it('should update the version metadata', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 69,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
|
||||
const newStorage = await migration70.migrate(oldStorage);
|
||||
expect(newStorage.meta).toStrictEqual({
|
||||
version: 70,
|
||||
});
|
||||
});
|
||||
|
||||
it('should migrate all data', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 69,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
PermissionLogController: {
|
||||
permissionActivityLog: [
|
||||
{
|
||||
id: 522690215,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://metamask.io',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
jsonrpc: '2.0',
|
||||
id: 522690215,
|
||||
origin: 'https://metamask.io',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1602643170686,
|
||||
response: {
|
||||
id: 522690215,
|
||||
jsonrpc: '2.0',
|
||||
result: [],
|
||||
},
|
||||
responseTime: 1602643170688,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 1620464600,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://widget.getacute.io',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
jsonrpc: '2.0',
|
||||
id: 1620464600,
|
||||
origin: 'https://widget.getacute.io',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1602643172935,
|
||||
response: {
|
||||
id: 1620464600,
|
||||
jsonrpc: '2.0',
|
||||
result: [],
|
||||
},
|
||||
responseTime: 1602643172935,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100021,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100021,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710669962,
|
||||
response: {
|
||||
id: 4279100021,
|
||||
jsonrpc: '2.0',
|
||||
result: [],
|
||||
},
|
||||
responseTime: 1620710669963,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100022,
|
||||
method: 'eth_requestAccounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_requestAccounts',
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100022,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710686872,
|
||||
response: {
|
||||
id: 4279100022,
|
||||
jsonrpc: '2.0',
|
||||
result: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'],
|
||||
},
|
||||
responseTime: 1620710693187,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100023,
|
||||
method: 'eth_requestAccounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_requestAccounts',
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100023,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710693204,
|
||||
response: {
|
||||
id: 4279100023,
|
||||
jsonrpc: '2.0',
|
||||
result: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'],
|
||||
},
|
||||
responseTime: 1620710693213,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100034,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
request: {
|
||||
method: 'eth_accounts',
|
||||
params: [],
|
||||
jsonrpc: '2.0',
|
||||
id: 4279100034,
|
||||
origin: 'https://app.uniswap.org',
|
||||
tabId: 5,
|
||||
},
|
||||
requestTime: 1620710712072,
|
||||
response: {
|
||||
id: 4279100034,
|
||||
jsonrpc: '2.0',
|
||||
result: ['0x64a845a5b02460acf8a3d84503b0d68d028b4bb4'],
|
||||
},
|
||||
responseTime: 1620710712075,
|
||||
success: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migration70.migrate(oldStorage);
|
||||
expect(newStorage).toStrictEqual({
|
||||
meta: {
|
||||
version: 70,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
PermissionLogController: {
|
||||
permissionActivityLog: [
|
||||
{
|
||||
id: 522690215,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://metamask.io',
|
||||
requestTime: 1602643170686,
|
||||
responseTime: 1602643170688,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 1620464600,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://widget.getacute.io',
|
||||
requestTime: 1602643172935,
|
||||
responseTime: 1602643172935,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100021,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
requestTime: 1620710669962,
|
||||
responseTime: 1620710669963,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100022,
|
||||
method: 'eth_requestAccounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
requestTime: 1620710686872,
|
||||
responseTime: 1620710693187,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100023,
|
||||
method: 'eth_requestAccounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
requestTime: 1620710693204,
|
||||
responseTime: 1620710693213,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
id: 4279100034,
|
||||
method: 'eth_accounts',
|
||||
methodType: 'restricted',
|
||||
origin: 'https://app.uniswap.org',
|
||||
requestTime: 1620710712072,
|
||||
responseTime: 1620710712075,
|
||||
success: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle missing PermissionLogController', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 69,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migration70.migrate(oldStorage);
|
||||
expect(newStorage).toStrictEqual({
|
||||
meta: {
|
||||
version: 70,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle missing PermissionLogController.permissionActivityLog', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 69,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
PermissionLogController: {},
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migration70.migrate(oldStorage);
|
||||
expect(newStorage).toStrictEqual({
|
||||
meta: {
|
||||
version: 70,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
PermissionLogController: {},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
28
app/scripts/migrations/071.js
Normal file
28
app/scripts/migrations/071.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
const version = 71;
|
||||
|
||||
/**
|
||||
* Renames NotificationController to AnnouncementController
|
||||
*/
|
||||
export default {
|
||||
version,
|
||||
async migrate(originalVersionedData) {
|
||||
const versionedData = cloneDeep(originalVersionedData);
|
||||
versionedData.meta.version = version;
|
||||
const state = versionedData.data;
|
||||
const newState = transformState(state);
|
||||
versionedData.data = newState;
|
||||
return versionedData;
|
||||
},
|
||||
};
|
||||
|
||||
function transformState(state) {
|
||||
if (state.NotificationController) {
|
||||
state.AnnouncementController = {
|
||||
announcements: state.NotificationController.notifications,
|
||||
};
|
||||
delete state.NotificationController;
|
||||
}
|
||||
return state;
|
||||
}
|
107
app/scripts/migrations/071.test.js
Normal file
107
app/scripts/migrations/071.test.js
Normal file
@ -0,0 +1,107 @@
|
||||
import migration71 from './071';
|
||||
|
||||
describe('migration #71', () => {
|
||||
it('should update the version metadata', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 70,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
|
||||
const newStorage = await migration71.migrate(oldStorage);
|
||||
expect(newStorage.meta).toStrictEqual({
|
||||
version: 71,
|
||||
});
|
||||
});
|
||||
|
||||
it('should rename NotificationController', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 70,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
NotificationController: {
|
||||
notifications: [
|
||||
{
|
||||
date: '2021-03-17',
|
||||
id: 1,
|
||||
image: {
|
||||
height: '230px',
|
||||
placeImageBelowDescription: true,
|
||||
src: 'images/mobile-link-qr.svg',
|
||||
width: '230px',
|
||||
},
|
||||
isShown: false,
|
||||
},
|
||||
{ date: '2021-03-08', id: 3, isShown: false },
|
||||
{
|
||||
date: '2021-05-11',
|
||||
id: 4,
|
||||
image: { src: 'images/source-logos-bsc.svg', width: '100%' },
|
||||
isShown: false,
|
||||
},
|
||||
{ date: '2021-06-09', id: 5, isShown: false },
|
||||
{ date: '2021-05-26', id: 6, isShown: false },
|
||||
{ date: '2021-09-17', id: 7, isShown: false },
|
||||
{ date: '2021-11-01', id: 8, isShown: false },
|
||||
{
|
||||
date: '2021-12-07',
|
||||
id: 9,
|
||||
image: { src: 'images/txinsights.png', width: '80%' },
|
||||
isShown: false,
|
||||
},
|
||||
{
|
||||
date: '2022-04-18',
|
||||
id: 10,
|
||||
image: { src: 'images/token-detection.svg', width: '100%' },
|
||||
isShown: false,
|
||||
},
|
||||
{ date: '2022-04-18', id: 11, isShown: false },
|
||||
{
|
||||
date: '2022-05-18',
|
||||
id: 12,
|
||||
image: { src: 'images/darkmode-banner.png', width: '100%' },
|
||||
isShown: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migration71.migrate(oldStorage);
|
||||
expect(newStorage).toStrictEqual({
|
||||
meta: {
|
||||
version: 71,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
AnnouncementController: {
|
||||
announcements: oldStorage.data.NotificationController.notifications,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle missing NotificationController', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 70,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migration71.migrate(oldStorage);
|
||||
expect(newStorage).toStrictEqual({
|
||||
meta: {
|
||||
version: 71,
|
||||
},
|
||||
data: {
|
||||
FooController: { a: 'b' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
@ -73,6 +73,8 @@ import m066 from './066';
|
||||
import m067 from './067';
|
||||
import m068 from './068';
|
||||
import m069 from './069';
|
||||
import m070 from './070';
|
||||
import m071 from './071';
|
||||
|
||||
const migrations = [
|
||||
m002,
|
||||
@ -143,6 +145,8 @@ const migrations = [
|
||||
m067,
|
||||
m068,
|
||||
m069,
|
||||
m070,
|
||||
m071,
|
||||
];
|
||||
|
||||
export default migrations;
|
||||
|
@ -51,6 +51,7 @@ require('eslint-plugin-node');
|
||||
require('eslint-plugin-prettier');
|
||||
require('eslint-plugin-react');
|
||||
require('eslint-plugin-react-hooks');
|
||||
require('eslint-plugin-jest');
|
||||
|
||||
defineAndRunBuildTasks();
|
||||
|
||||
|
@ -473,21 +473,21 @@ function createFactoredBuild({
|
||||
groupSet,
|
||||
commonSet,
|
||||
browserPlatforms,
|
||||
useLavamoat: false,
|
||||
useLavamoat: true,
|
||||
});
|
||||
renderHtmlFile({
|
||||
htmlName: 'notification',
|
||||
groupSet,
|
||||
commonSet,
|
||||
browserPlatforms,
|
||||
useLavamoat: false,
|
||||
useLavamoat: true,
|
||||
});
|
||||
renderHtmlFile({
|
||||
htmlName: 'home',
|
||||
groupSet,
|
||||
commonSet,
|
||||
browserPlatforms,
|
||||
useLavamoat: false,
|
||||
useLavamoat: true,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -55,6 +55,22 @@
|
||||
"globals": {
|
||||
"localStorage": true
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"globals": {
|
||||
"HTMLIFrameElement": true
|
||||
}
|
||||
},
|
||||
"react-devtools": {
|
||||
"packages": {
|
||||
"react-devtools-core": true
|
||||
}
|
||||
},
|
||||
"react-devtools-core": {
|
||||
"globals": {
|
||||
"setTimeout": true,
|
||||
"WebSocket": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -733,8 +733,10 @@
|
||||
"Worker": true,
|
||||
"clearTimeout": true,
|
||||
"console.error": true,
|
||||
"console.info": true,
|
||||
"console.log": true,
|
||||
"console.warn": true,
|
||||
"fetch": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
@ -747,7 +749,6 @@
|
||||
"ajv": true,
|
||||
"buffer": true,
|
||||
"concat-stream": true,
|
||||
"cross-fetch": true,
|
||||
"crypto-browserify": true,
|
||||
"eth-rpc-errors": true,
|
||||
"fast-deep-equal": true,
|
||||
|
@ -50,6 +50,22 @@
|
||||
"globals": {
|
||||
"localStorage": true
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"globals": {
|
||||
"HTMLIFrameElement": true
|
||||
}
|
||||
},
|
||||
"react-devtools": {
|
||||
"packages": {
|
||||
"react-devtools-core": true
|
||||
}
|
||||
},
|
||||
"react-devtools-core": {
|
||||
"globals": {
|
||||
"setTimeout": true,
|
||||
"WebSocket": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -751,8 +751,10 @@
|
||||
"Worker": true,
|
||||
"clearTimeout": true,
|
||||
"console.error": true,
|
||||
"console.info": true,
|
||||
"console.log": true,
|
||||
"console.warn": true,
|
||||
"fetch": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
@ -765,7 +767,6 @@
|
||||
"ajv": true,
|
||||
"buffer": true,
|
||||
"concat-stream": true,
|
||||
"cross-fetch": true,
|
||||
"crypto-browserify": true,
|
||||
"eth-rpc-errors": true,
|
||||
"fast-deep-equal": true,
|
||||
|
@ -55,6 +55,22 @@
|
||||
"globals": {
|
||||
"localStorage": true
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"globals": {
|
||||
"HTMLIFrameElement": true
|
||||
}
|
||||
},
|
||||
"react-devtools": {
|
||||
"packages": {
|
||||
"react-devtools-core": true
|
||||
}
|
||||
},
|
||||
"react-devtools-core": {
|
||||
"globals": {
|
||||
"setTimeout": true,
|
||||
"WebSocket": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -733,8 +733,10 @@
|
||||
"Worker": true,
|
||||
"clearTimeout": true,
|
||||
"console.error": true,
|
||||
"console.info": true,
|
||||
"console.log": true,
|
||||
"console.warn": true,
|
||||
"fetch": true,
|
||||
"setTimeout": true
|
||||
},
|
||||
"packages": {
|
||||
@ -747,7 +749,6 @@
|
||||
"ajv": true,
|
||||
"buffer": true,
|
||||
"concat-stream": true,
|
||||
"cross-fetch": true,
|
||||
"crypto-browserify": true,
|
||||
"eth-rpc-errors": true,
|
||||
"fast-deep-equal": true,
|
||||
|
@ -2,20 +2,20 @@
|
||||
"resources": {
|
||||
"@babel/core": {
|
||||
"packages": {
|
||||
"<root>": true,
|
||||
"$root$": true,
|
||||
"@babel/preset-env": true,
|
||||
"@babel/preset-react": true,
|
||||
"@babel/plugin-transform-runtime": true,
|
||||
"@babel/plugin-proposal-class-properties": true,
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": true,
|
||||
"@babel/plugin-proposal-object-rest-spread": true,
|
||||
"@babel/plugin-proposal-optional-chaining": true,
|
||||
"@babel/plugin-transform-runtime": true,
|
||||
"@babel/preset-env": true,
|
||||
"@babel/preset-react": true,
|
||||
"@babel/preset-typescript": true
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"eslint>@eslint/eslintrc": {
|
||||
"packages": {
|
||||
"<root>": true,
|
||||
"$root$": true,
|
||||
"@babel/eslint-parser": true,
|
||||
"@babel/eslint-plugin": true,
|
||||
"@metamask/eslint-config": true,
|
||||
@ -32,58 +32,56 @@
|
||||
"eslint-plugin-react-hooks": true
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"eslint-plugin-jest": {
|
||||
"packages": {
|
||||
"@typescript-eslint/experimental-utils": true,
|
||||
"@typescript-eslint/scope-manager": true,
|
||||
"debug": true,
|
||||
"eslint": true,
|
||||
"ignore": true,
|
||||
"regexpp": true,
|
||||
"semver": true,
|
||||
"tsutils": true,
|
||||
"typescript": true
|
||||
"eslint-plugin-jest>@typescript-eslint/experimental-utils": true,
|
||||
"@typescript-eslint/eslint-plugin": true
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/experimental-utils": {
|
||||
"eslint-plugin-jest>@typescript-eslint/experimental-utils": {
|
||||
"builtin": {
|
||||
"path": true
|
||||
},
|
||||
"packages": {
|
||||
"@typescript-eslint/scope-manager": true,
|
||||
"@typescript-eslint/types": true,
|
||||
"eslint-plugin-jest>@typescript-eslint/experimental-utils>eslint-utils": true,
|
||||
"@typescript-eslint/parser>@typescript-eslint/types": true,
|
||||
"eslint": true,
|
||||
"eslint-scope": true,
|
||||
"eslint-utils": true
|
||||
"@typescript-eslint/parser>@typescript-eslint/scope-manager": true,
|
||||
"eslint>eslint-scope": true
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"eslint-plugin-jest>@typescript-eslint/experimental-utils>eslint-utils": {
|
||||
"packages": {
|
||||
"@typescript-eslint/types": true,
|
||||
"@typescript-eslint/visitor-keys": true
|
||||
"eslint-plugin-jest>@typescript-eslint/experimental-utils>eslint-utils>eslint-visitor-keys": true
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"packages": {
|
||||
"eslint-visitor-keys": true
|
||||
"typescript": true,
|
||||
"eslint-plugin-jest>@typescript-eslint/experimental-utils": true,
|
||||
"@typescript-eslint/parser>@typescript-eslint/scope-manager": true,
|
||||
"@typescript-eslint/eslint-plugin>tsutils": true,
|
||||
"eslint>debug": true,
|
||||
"eslint": true,
|
||||
"semver": true,
|
||||
"globby>ignore": true,
|
||||
"eslint>regexpp": true
|
||||
}
|
||||
},
|
||||
"eslint-module-utils": {
|
||||
"eslint-plugin-import>eslint-module-utils": {
|
||||
"packages": {
|
||||
"@babel/eslint-parser": true,
|
||||
"@typescript-eslint/parser": true,
|
||||
"eslint-import-resolver-node": true,
|
||||
"eslint-import-resolver-typescript": true
|
||||
}
|
||||
},
|
||||
"module-deps": {
|
||||
"packages": {
|
||||
"loose-envify": true
|
||||
"@babel/eslint-parser": true
|
||||
}
|
||||
},
|
||||
"node-sass": {
|
||||
"native": true
|
||||
},
|
||||
"browserify>module-deps": {
|
||||
"packages": {
|
||||
"loose-envify": true
|
||||
}
|
||||
},
|
||||
"sass": {
|
||||
"env": "unfrozen",
|
||||
"builtin": {
|
||||
|
File diff suppressed because it is too large
Load Diff
83
package.json
83
package.json
@ -114,22 +114,22 @@
|
||||
"@keystonehq/metamask-airgapped-keyring": "0.2.1",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@metamask/contract-metadata": "^1.31.0",
|
||||
"@metamask/controllers": "^27.0.0",
|
||||
"@metamask/controllers": "^28.0.0",
|
||||
"@metamask/design-tokens": "^1.5.1",
|
||||
"@metamask/eth-ledger-bridge-keyring": "^0.11.0",
|
||||
"@metamask/eth-token-tracker": "^4.0.0",
|
||||
"@metamask/etherscan-link": "^2.1.0",
|
||||
"@metamask/iframe-execution-environment-service": "^0.10.7",
|
||||
"@metamask/iframe-execution-environment-service": "^0.11.1",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@metamask/logo": "^3.1.1",
|
||||
"@metamask/metamask-eth-abis": "^3.0.0",
|
||||
"@metamask/obs-store": "^5.0.0",
|
||||
"@metamask/post-message-stream": "^4.0.0",
|
||||
"@metamask/providers": "^8.1.1",
|
||||
"@metamask/rpc-methods": "^0.10.7",
|
||||
"@metamask/rpc-methods": "^0.11.1",
|
||||
"@metamask/slip44": "^2.0.0",
|
||||
"@metamask/smart-transactions-controller": "^1.10.0",
|
||||
"@metamask/snap-controllers": "^0.10.7",
|
||||
"@metamask/snap-controllers": "^0.11.1",
|
||||
"@ngraveio/bc-ur": "^1.1.6",
|
||||
"@popperjs/core": "^2.4.0",
|
||||
"@reduxjs/toolkit": "^1.6.2",
|
||||
@ -174,10 +174,8 @@
|
||||
"ethjs-query": "^0.3.4",
|
||||
"extension-port-stream": "^2.0.0",
|
||||
"fast-json-patch": "^2.2.1",
|
||||
"fast-safe-stringify": "^2.0.7",
|
||||
"fuse.js": "^3.2.0",
|
||||
"globalthis": "^1.0.1",
|
||||
"human-standard-collectible-abi": "^1.0.2",
|
||||
"human-standard-token-abi": "^2.0.0",
|
||||
"immer": "^9.0.6",
|
||||
"json-rpc-engine": "^6.1.0",
|
||||
@ -243,7 +241,7 @@
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
"@babel/register": "^7.5.5",
|
||||
"@lavamoat/allow-scripts": "^2.0.0",
|
||||
"@lavamoat/allow-scripts": "^2.0.3",
|
||||
"@lavamoat/lavapack": "^2.0.4",
|
||||
"@metamask/auto-changelog": "^2.1.0",
|
||||
"@metamask/eslint-config": "^9.0.0",
|
||||
@ -328,7 +326,7 @@
|
||||
"jest-canvas-mock": "^2.3.1",
|
||||
"jsdom": "^11.2.0",
|
||||
"koa": "^2.7.0",
|
||||
"lavamoat": "^5.3.5",
|
||||
"lavamoat": "^6.1.2",
|
||||
"lavamoat-browserify": "^14.1.0",
|
||||
"lavamoat-viz": "^6.0.9",
|
||||
"lockfile-lint": "^4.0.0",
|
||||
@ -385,59 +383,62 @@
|
||||
},
|
||||
"lavamoat": {
|
||||
"allowScripts": {
|
||||
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>leveldown": false,
|
||||
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>libp2p-crypto-secp256k1>secp256k1": false,
|
||||
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>libp2p-crypto>libp2p-crypto-secp256k1>secp256k1": false,
|
||||
"3box>3box-orbitdb-plugins>ipfs-log>orbit-db-identity-provider>orbit-db-keystore>libp2p-crypto>ursa-optional": false,
|
||||
"@sentry/cli": true,
|
||||
"chromedriver": true,
|
||||
"geckodriver": true,
|
||||
"react-devtools>electron": true,
|
||||
"3box>ipfs-postmsg-proxy>peer-id>libp2p-crypto>libp2p-crypto-secp256k1>secp256k1": false,
|
||||
"3box>ipfs>ipfs-mfs>ipfs-unixfs-exporter>ipfs-unixfs-importer>rabin-wasm>assemblyscript": false,
|
||||
"3box>ipfs>ipfs-repo>datastore-level>leveldown": false,
|
||||
"3box>ipfs>ipld-bitcoin>bitcoinjs-lib>bip32>tiny-secp256k1": false,
|
||||
"3box>ipfs>ipfs-unixfs-importer>rabin-wasm>assemblyscript": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-account>ethereumjs-util>keccak": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-account>ethereumjs-util>secp256k1": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-tx>ethereumjs-util>ethereum-cryptography>keccak": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-tx>ethereumjs-util>ethereum-cryptography>secp256k1": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-util>keccak": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-block>ethereumjs-util>secp256k1": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-block>merkle-patricia-tree>ethereumjs-util>keccak": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-block>merkle-patricia-tree>ethereumjs-util>secp256k1": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-tx>ethereumjs-util>keccak": false,
|
||||
"3box>ipfs>ipld-ethereum>ethereumjs-tx>ethereumjs-util>secp256k1": false,
|
||||
"3box>ipfs>ipld-ethereum>merkle-patricia-tree>ethereumjs-util>keccak": false,
|
||||
"3box>ipfs>ipld-ethereum>merkle-patricia-tree>ethereumjs-util>secp256k1": false,
|
||||
"3box>ipfs>libp2p-crypto>libp2p-crypto-secp256k1>secp256k1": false,
|
||||
"3box>ipfs>libp2p-crypto>ursa-optional": false,
|
||||
"3box>ipfs>prometheus-gc-stats>gc-stats": false,
|
||||
"3box>orbit-db>orbit-db-cache>leveldown": false,
|
||||
"@lavamoat/allow-scripts>@lavamoat/preinstall-always-fail": false,
|
||||
"@metamask/controllers>babel-runtime>core-js": false,
|
||||
"@metamask/controllers>eth-json-rpc-infura>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"@metamask/controllers>eth-json-rpc-infura>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"@metamask/controllers>eth-keyring-controller>eth-hd-keyring>eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"@metamask/controllers>eth-keyring-controller>eth-hd-keyring>eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"@metamask/controllers>web3-provider-engine>eth-json-rpc-filters>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"@metamask/controllers>web3-provider-engine>eth-json-rpc-filters>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"@metamask/controllers>web3-provider-engine>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"@metamask/controllers>web3-provider-engine>eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"3box>orbit-db>orbit-db-keystore>leveldown": false,
|
||||
"3box>orbit-db>orbit-db-keystore>libp2p-crypto-secp256k1>secp256k1": false,
|
||||
"@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>@ledgerhq/hw-transport-node-hid-noevents>node-hid": false,
|
||||
"@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>node-hid": false,
|
||||
"@eth-optimism/contracts>@ethersproject/hardware-wallets>@ledgerhq/hw-transport-node-hid>usb": false,
|
||||
"@metamask/controllers>web3-provider-engine>ethereumjs-util>keccak": false,
|
||||
"@metamask/controllers>web3-provider-engine>ethereumjs-util>secp256k1": false,
|
||||
"@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>keccak": false,
|
||||
"@metamask/controllers>web3-provider-engine>ethereumjs-vm>merkle-patricia-tree>ethereumjs-util>secp256k1": false,
|
||||
"@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"@metamask/eth-ledger-bridge-keyring>eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"@sentry/cli": true,
|
||||
"@storybook/addon-a11y>@storybook/addons>@storybook/api>@storybook/channels>core-js": false,
|
||||
"@storybook/addon-essentials>@storybook/addon-docs>@storybook/builder-webpack4>@storybook/ui>core-js-pure": false,
|
||||
"chromedriver": true,
|
||||
"@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": false,
|
||||
"@storybook/api>core-js": false,
|
||||
"@storybook/core>@storybook/core-client>@storybook/ui>core-js-pure": false,
|
||||
"eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>keccak": false,
|
||||
"eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false,
|
||||
"eth-json-rpc-infura>eth-json-rpc-middleware>ethereumjs-util>keccak": false,
|
||||
"eth-json-rpc-infura>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false,
|
||||
"eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"eth-lattice-keyring>gridplus-sdk": false,
|
||||
"eth-sig-util>ethereumjs-util>keccak": false,
|
||||
"eth-sig-util>ethereumjs-util>secp256k1": false,
|
||||
"eth-trezor-keyring>hdkey>secp256k1": false,
|
||||
"eth-trezor-keyring>trezor-connect>@trezor/transport>protobufjs": false,
|
||||
"eth-trezor-keyring>trezor-connect>@trezor/utxo-lib>blake-hash": false,
|
||||
"eth-trezor-keyring>trezor-connect>trezor-link>protobufjs": false,
|
||||
"eth-trezor-keyring>trezor-connect>@trezor/utxo-lib>tiny-secp256k1": false,
|
||||
"ethereumjs-util>ethereum-cryptography>keccak": false,
|
||||
"ethjs-query>babel-runtime>core-js": false,
|
||||
"ganache>@trufflesuite/bigint-buffer": false,
|
||||
"ganache>bufferutil": false,
|
||||
"ganache>keccak": false,
|
||||
"ganache>leveldown": false,
|
||||
"geckodriver": true,
|
||||
"react-devtools>electron": true,
|
||||
"eth-trezor-keyring>trezor-connect>@trezor/transport>protobufjs": false,
|
||||
"@metamask/iframe-execution-environment-service>@metamask/execution-environments": false,
|
||||
"@metamask/snap-controllers>@metamask/execution-environments": false,
|
||||
"@metamask/iframe-execution-environment-service>@metamask/snap-controllers>@metamask/execution-environments": false,
|
||||
"@metamask/rpc-methods>@metamask/snap-controllers>@metamask/execution-environments": false
|
||||
"ganache>secp256k1": false,
|
||||
"ganache>utf-8-validate": false,
|
||||
"gulp-watch>chokidar>fsevents": false,
|
||||
"gulp>glob-watcher>chokidar>fsevents": false,
|
||||
"webpack>watchpack>watchpack-chokidar2>chokidar>fsevents": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
patches/zxcvbn+4.4.2.patch
Normal file
13
patches/zxcvbn+4.4.2.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/zxcvbn/lib/matching.js b/node_modules/zxcvbn/lib/matching.js
|
||||
index 3940bad..748da8b 100644
|
||||
--- a/node_modules/zxcvbn/lib/matching.js
|
||||
+++ b/node_modules/zxcvbn/lib/matching.js
|
||||
@@ -13,7 +13,7 @@ build_ranked_dict = function(ordered_list) {
|
||||
i = 1;
|
||||
for (o = 0, len1 = ordered_list.length; o < len1; o++) {
|
||||
word = ordered_list[o];
|
||||
- result[word] = i;
|
||||
+ Reflect.defineProperty(result, word, { value: i, configurable: true, enumerable: true, writable: true });
|
||||
i += 1;
|
||||
}
|
||||
return result;
|
@ -70,3 +70,25 @@ export const POLLING_TOKEN_ENVIRONMENT_TYPES = {
|
||||
[ENVIRONMENT_TYPE_NOTIFICATION]: 'notificationGasPollTokens',
|
||||
[ENVIRONMENT_TYPE_FULLSCREEN]: 'fullScreenGasPollTokens',
|
||||
};
|
||||
|
||||
export const ORIGIN_METAMASK = 'metamask';
|
||||
|
||||
export const METAMASK_BETA_CHROME_ID = 'pbbkamfgmaedccnfkmjcofcecjhfgldn';
|
||||
export const METAMASK_PROD_CHROME_ID = 'nkbihfbeogaeaoehlefnkodbefgpgknn';
|
||||
export const METAMASK_FLASK_CHROME_ID = 'ljfoeinjpaedjfecbmggjgodbgkmjkjk';
|
||||
|
||||
export const CHROME_BUILD_IDS = [
|
||||
METAMASK_BETA_CHROME_ID,
|
||||
METAMASK_PROD_CHROME_ID,
|
||||
METAMASK_FLASK_CHROME_ID,
|
||||
];
|
||||
|
||||
const METAMASK_BETA_FIREFOX_ID = 'webextension-beta@metamask.io';
|
||||
const METAMASK_PROD_FIREFOX_ID = 'webextension@metamask.io';
|
||||
const METAMASK_FLASK_FIREFOX_ID = 'webextension-flask@metamask.io';
|
||||
|
||||
export const FIREFOX_BUILD_IDS = [
|
||||
METAMASK_BETA_FIREFOX_ID,
|
||||
METAMASK_PROD_FIREFOX_ID,
|
||||
METAMASK_FLASK_FIREFOX_ID,
|
||||
];
|
||||
|
@ -170,6 +170,7 @@
|
||||
* change, we identify the new number_of_accounts trait
|
||||
* @property {'number_of_nft_collections'} NUMBER_OF_NFT_COLLECTIONS - user
|
||||
* trait for number of unique NFT addresses
|
||||
* @property {'number_of_nfts'} NUMBER_OF_NFTS - user trait for number of all NFT addresses
|
||||
* @property {'number_of_tokens'} NUMBER_OF_TOKENS - when the number of tokens change, we
|
||||
* identify the new number_of_tokens trait
|
||||
* @property {'opensea_api_enabled'} OPENSEA_API_ENABLED - when the OpenSea API is enabled
|
||||
@ -191,6 +192,7 @@ export const TRAITS = {
|
||||
NFT_AUTODETECTION_ENABLED: 'nft_autodetection_enabled',
|
||||
NUMBER_OF_ACCOUNTS: 'number_of_accounts',
|
||||
NUMBER_OF_NFT_COLLECTIONS: 'number_of_nft_collections',
|
||||
NUMBER_OF_NFTS: 'number_of_nfts',
|
||||
NUMBER_OF_TOKENS: 'number_of_tokens',
|
||||
OPENSEA_API_ENABLED: 'opensea_api_enabled',
|
||||
THREE_BOX_ENABLED: 'three_box_enabled',
|
||||
@ -211,6 +213,8 @@ export const TRAITS = {
|
||||
* of identities(accounts) added to the user's MetaMask.
|
||||
* @property {number} [number_of_nft_collections] - A number representing the
|
||||
* amount of different NFT collections the user possesses an NFT from.
|
||||
* @property {number} [number_of_nfts] - A number representing the
|
||||
* amount of all NFTs the user possesses across all networks and accounts.
|
||||
* @property {number} [number_of_tokens] - The total number of token contracts
|
||||
* the user has across all networks and accounts.
|
||||
* @property {boolean} [opensea_api_enabled] - does the user have the OpenSea
|
||||
@ -256,9 +260,32 @@ export const REJECT_NOTFICIATION_CLOSE = 'Cancel Via Notification Close';
|
||||
export const REJECT_NOTFICIATION_CLOSE_SIG =
|
||||
'Cancel Sig Request Via Notification Close';
|
||||
|
||||
/**
|
||||
* EVENTS
|
||||
*/
|
||||
|
||||
export const EVENT_NAMES = {
|
||||
SIGNATURE_REQUESTED: 'Signature Requested',
|
||||
ENCRYPTION_PUBLIC_KEY_REQUESTED: 'Encryption Public Key Requested',
|
||||
DECRYPTION_REQUESTED: 'Decryption Requested',
|
||||
PERMISSIONS_REQUESTED: 'Permissions Requested',
|
||||
};
|
||||
|
||||
export const EVENT = {
|
||||
CATEGORIES: {
|
||||
ACCOUNTS: 'Accounts',
|
||||
AUTH: 'Auth',
|
||||
BACKGROUND: 'Background',
|
||||
INPAGE_PROVIDER: 'inpage_provider',
|
||||
MESSAGES: 'Messages',
|
||||
NAVIGATION: 'Navigation',
|
||||
NETWORK: 'Network',
|
||||
ONBOARDING: 'Onboarding',
|
||||
RETENTION: 'Retention',
|
||||
SETTINGS: 'Settings',
|
||||
SNAPS: 'Snaps',
|
||||
SWAPS: 'Swaps',
|
||||
TRANSACTIONS: 'Transactions',
|
||||
WALLET: 'Wallet',
|
||||
},
|
||||
};
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { capitalize } from 'lodash';
|
||||
|
||||
export const ROPSTEN = 'ropsten';
|
||||
export const RINKEBY = 'rinkeby';
|
||||
export const KOVAN = 'kovan';
|
||||
@ -79,16 +81,45 @@ export const TEST_CHAINS = [
|
||||
LOCALHOST_CHAIN_ID,
|
||||
];
|
||||
|
||||
export const TEST_NETWORK_TICKER_MAP = {
|
||||
[ROPSTEN]: `${capitalize(ROPSTEN)}${ETH_SYMBOL}`,
|
||||
[RINKEBY]: `${capitalize(RINKEBY)}${ETH_SYMBOL}`,
|
||||
[KOVAN]: `${capitalize(KOVAN)}${ETH_SYMBOL}`,
|
||||
[GOERLI]: `${capitalize(GOERLI)}${ETH_SYMBOL}`,
|
||||
};
|
||||
|
||||
/**
|
||||
* Map of all build-in Infura networks to their network and chain IDs.
|
||||
* Map of all build-in Infura networks to their network, ticker and chain IDs.
|
||||
*/
|
||||
export const NETWORK_TYPE_TO_ID_MAP = {
|
||||
[ROPSTEN]: { networkId: ROPSTEN_NETWORK_ID, chainId: ROPSTEN_CHAIN_ID },
|
||||
[RINKEBY]: { networkId: RINKEBY_NETWORK_ID, chainId: RINKEBY_CHAIN_ID },
|
||||
[KOVAN]: { networkId: KOVAN_NETWORK_ID, chainId: KOVAN_CHAIN_ID },
|
||||
[GOERLI]: { networkId: GOERLI_NETWORK_ID, chainId: GOERLI_CHAIN_ID },
|
||||
[MAINNET]: { networkId: MAINNET_NETWORK_ID, chainId: MAINNET_CHAIN_ID },
|
||||
[LOCALHOST]: { networkId: LOCALHOST_NETWORK_ID, chainId: LOCALHOST_CHAIN_ID },
|
||||
[ROPSTEN]: {
|
||||
networkId: ROPSTEN_NETWORK_ID,
|
||||
chainId: ROPSTEN_CHAIN_ID,
|
||||
ticker: TEST_NETWORK_TICKER_MAP[ROPSTEN],
|
||||
},
|
||||
[RINKEBY]: {
|
||||
networkId: RINKEBY_NETWORK_ID,
|
||||
chainId: RINKEBY_CHAIN_ID,
|
||||
ticker: TEST_NETWORK_TICKER_MAP[RINKEBY],
|
||||
},
|
||||
[KOVAN]: {
|
||||
networkId: KOVAN_NETWORK_ID,
|
||||
chainId: KOVAN_CHAIN_ID,
|
||||
ticker: TEST_NETWORK_TICKER_MAP[KOVAN],
|
||||
},
|
||||
[GOERLI]: {
|
||||
networkId: GOERLI_NETWORK_ID,
|
||||
chainId: GOERLI_CHAIN_ID,
|
||||
ticker: TEST_NETWORK_TICKER_MAP[GOERLI],
|
||||
},
|
||||
[MAINNET]: {
|
||||
networkId: MAINNET_NETWORK_ID,
|
||||
chainId: MAINNET_CHAIN_ID,
|
||||
},
|
||||
[LOCALHOST]: {
|
||||
networkId: LOCALHOST_NETWORK_ID,
|
||||
chainId: LOCALHOST_CHAIN_ID,
|
||||
},
|
||||
};
|
||||
|
||||
export const NETWORK_TO_NAME_MAP = {
|
||||
@ -135,6 +166,7 @@ export const CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP = {
|
||||
[AVALANCHE_CHAIN_ID]: AVAX_TOKEN_IMAGE_URL,
|
||||
[BSC_CHAIN_ID]: BNB_TOKEN_IMAGE_URL,
|
||||
[POLYGON_CHAIN_ID]: MATIC_TOKEN_IMAGE_URL,
|
||||
[ROPSTEN_CHAIN_ID]: TEST_ETH_TOKEN_IMAGE_URL,
|
||||
};
|
||||
|
||||
export const CHAIN_ID_TO_NETWORK_ID_MAP = Object.values(
|
||||
@ -207,19 +239,19 @@ export const BUYABLE_CHAINS_MAP = {
|
||||
},
|
||||
},
|
||||
[ROPSTEN_CHAIN_ID]: {
|
||||
nativeCurrency: ETH_SYMBOL,
|
||||
nativeCurrency: TEST_NETWORK_TICKER_MAP[ROPSTEN],
|
||||
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
|
||||
},
|
||||
[RINKEBY_CHAIN_ID]: {
|
||||
nativeCurrency: ETH_SYMBOL,
|
||||
nativeCurrency: TEST_NETWORK_TICKER_MAP[RINKEBY],
|
||||
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
|
||||
},
|
||||
[GOERLI_CHAIN_ID]: {
|
||||
nativeCurrency: ETH_SYMBOL,
|
||||
nativeCurrency: TEST_NETWORK_TICKER_MAP[GOERLI],
|
||||
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
|
||||
},
|
||||
[KOVAN_CHAIN_ID]: {
|
||||
nativeCurrency: ETH_SYMBOL,
|
||||
nativeCurrency: TEST_NETWORK_TICKER_MAP[KOVAN],
|
||||
network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME,
|
||||
},
|
||||
[BSC_CHAIN_ID]: {
|
||||
|
@ -19,7 +19,7 @@
|
||||
"type": "0x2"
|
||||
},
|
||||
"origin": "metamask",
|
||||
"type": "sentEther",
|
||||
"type": "simpleSend",
|
||||
"history": [
|
||||
{
|
||||
"id": 6854191329910881,
|
||||
@ -39,7 +39,7 @@
|
||||
"type": "0x2"
|
||||
},
|
||||
"origin": "metamask",
|
||||
"type": "sentEther"
|
||||
"type": "simpleSend"
|
||||
},
|
||||
[
|
||||
{
|
||||
@ -95,7 +95,7 @@
|
||||
"type": "0x2"
|
||||
},
|
||||
"origin": "metamask",
|
||||
"type": "sentEther",
|
||||
"type": "simpleSend",
|
||||
"history": [
|
||||
{
|
||||
"id": 6854191329910881,
|
||||
@ -115,7 +115,7 @@
|
||||
"type": "0x2"
|
||||
},
|
||||
"origin": "metamask",
|
||||
"type": "sentEther"
|
||||
"type": "simpleSend"
|
||||
},
|
||||
[
|
||||
{
|
||||
@ -172,7 +172,7 @@
|
||||
"type": "0x2"
|
||||
},
|
||||
"origin": "metamask",
|
||||
"type": "sentEther",
|
||||
"type": "simpleSend",
|
||||
"history": [
|
||||
{
|
||||
"id": 6854191329910881,
|
||||
@ -192,7 +192,7 @@
|
||||
"type": "0x2"
|
||||
},
|
||||
"origin": "metamask",
|
||||
"type": "sentEther"
|
||||
"type": "simpleSend"
|
||||
},
|
||||
[
|
||||
{
|
||||
|
@ -386,6 +386,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PermissionsController": {
|
||||
"permissionsRequests": [],
|
||||
"permissionsDescriptions": {},
|
||||
"domains": {
|
||||
"http://127.0.0.1:8080": {
|
||||
"permissions": [
|
||||
{
|
||||
"@context": ["https://github.com/MetaMask/rpc-cap"],
|
||||
"parentCapability": "eth_accounts",
|
||||
"id": "f55a1c15-ea48-4088-968e-63be474d42fa",
|
||||
"date": 1594348332268,
|
||||
"invoker": "http://127.0.0.1:8080",
|
||||
"caveats": [
|
||||
{
|
||||
"type": "limitResponseLength",
|
||||
"value": 1,
|
||||
"name": "primaryAccountOnly"
|
||||
},
|
||||
{
|
||||
"type": "filterResponse",
|
||||
"value": ["0x5cfe73b6021e818b776b421b1c4db2474086a7e1"],
|
||||
"name": "exposedAccounts"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {},
|
||||
"firstTimeInfo": {
|
||||
"date": 1575697234195,
|
||||
|
@ -555,11 +555,6 @@ describe('MetaMask', function () {
|
||||
});
|
||||
|
||||
it('displays the token approval data', async function () {
|
||||
await driver.clickElement(
|
||||
'.confirm-approve-content__view-full-tx-button',
|
||||
);
|
||||
await driver.delay(regularDelayMs);
|
||||
|
||||
const functionType = await driver.findElement(
|
||||
'.confirm-approve-content__data .confirm-approve-content__small-text',
|
||||
);
|
||||
@ -750,11 +745,6 @@ describe('MetaMask', function () {
|
||||
});
|
||||
|
||||
it('shows the correct recipient', async function () {
|
||||
await driver.clickElement(
|
||||
'.confirm-approve-content__view-full-tx-button',
|
||||
);
|
||||
await driver.delay(regularDelayMs);
|
||||
|
||||
const permissionInfo = await driver.findElements(
|
||||
'.confirm-approve-content__medium-text',
|
||||
);
|
||||
|
@ -69,15 +69,19 @@ async function main() {
|
||||
throw error;
|
||||
}
|
||||
|
||||
let testTimeoutInMilliseconds = 60 * 1000;
|
||||
|
||||
if (leaveRunning) {
|
||||
process.env.E2E_LEAVE_RUNNING = 'true';
|
||||
testTimeoutInMilliseconds = 0;
|
||||
}
|
||||
|
||||
await retry({ retries }, async () => {
|
||||
await runInShell('yarn', [
|
||||
'mocha',
|
||||
'--no-config',
|
||||
'--no-timeouts',
|
||||
'--timeout',
|
||||
testTimeoutInMilliseconds,
|
||||
e2eTestPath,
|
||||
]);
|
||||
});
|
||||
|
94
test/e2e/snaps/test-snap-bip-44.spec.js
Normal file
94
test/e2e/snaps/test-snap-bip-44.spec.js
Normal file
@ -0,0 +1,94 @@
|
||||
const { strict: assert } = require('assert');
|
||||
const { withFixtures } = require('../helpers');
|
||||
|
||||
describe('Test Snap bip-44', function () {
|
||||
it('can pop up bip-44 snap and get private key result', async function () {
|
||||
const ganacheOptions = {
|
||||
accounts: [
|
||||
{
|
||||
secretKey:
|
||||
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
|
||||
balance: 25000000000000000000,
|
||||
},
|
||||
],
|
||||
};
|
||||
await withFixtures(
|
||||
{
|
||||
fixtures: 'imported-account',
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
driverOptions: {
|
||||
type: 'flask',
|
||||
},
|
||||
},
|
||||
async ({ driver }) => {
|
||||
await driver.navigate();
|
||||
|
||||
// enter pw into extension
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
|
||||
// navigate to test snaps page and connect
|
||||
await driver.driver.get('https://metamask.github.io/test-snaps/0.1.3/');
|
||||
await driver.fill('.snapId3', 'npm:@metamask/test-snap-bip44');
|
||||
await driver.clickElement({
|
||||
text: 'Connect BIP-44 Snap',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// switch to metamask extension and click connect
|
||||
await driver.waitUntilXWindowHandles(2, 5000, 10000);
|
||||
let windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement(
|
||||
{
|
||||
text: 'Connect',
|
||||
tag: 'button',
|
||||
},
|
||||
10000,
|
||||
);
|
||||
|
||||
await driver.delay(2000);
|
||||
|
||||
// approve install of snap
|
||||
await driver.waitUntilXWindowHandles(2, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.clickElement({
|
||||
text: 'Approve & Install',
|
||||
tag: 'button',
|
||||
});
|
||||
// deal with permissions popover
|
||||
await driver.delay(1000);
|
||||
await driver.press('#warning-accept', driver.Key.SPACE);
|
||||
await driver.clickElement({
|
||||
text: 'Confirm',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// click send inputs on test snap page
|
||||
await driver.waitUntilXWindowHandles(1, 5000, 10000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle('Test Snaps', windowHandles);
|
||||
await driver.clickElement({
|
||||
text: 'Send Test to BIP-44 Snap',
|
||||
tag: 'button',
|
||||
});
|
||||
|
||||
// check the results of the public key test
|
||||
await driver.delay(2000);
|
||||
const bip44Result = await driver.findElement('.bip44Result');
|
||||
assert.equal(
|
||||
await bip44Result.getText(),
|
||||
'Public key: "0x86debb44fb3a984d93f326131d4c1db0bc39644f1a67b673b3ab45941a1cea6a385981755185ac4594b6521e4d1e8d1"',
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
@ -1,9 +1,5 @@
|
||||
const { strict: assert } = require('assert');
|
||||
const {
|
||||
convertToHexValue,
|
||||
withFixtures,
|
||||
regularDelayMs,
|
||||
} = require('../helpers');
|
||||
const { convertToHexValue, withFixtures } = require('../helpers');
|
||||
|
||||
describe('Deploy contract and call contract methods', function () {
|
||||
const ganacheOptions = {
|
||||
@ -19,7 +15,7 @@ describe('Deploy contract and call contract methods', function () {
|
||||
await withFixtures(
|
||||
{
|
||||
dapp: true,
|
||||
fixtures: 'imported-account',
|
||||
fixtures: 'connected-state',
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
},
|
||||
@ -28,32 +24,17 @@ describe('Deploy contract and call contract methods', function () {
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
|
||||
// connects the dapp
|
||||
// deploy contract
|
||||
await driver.openNewPage('http://127.0.0.1:8080/');
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.clickElement('#deployButton');
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
await driver.delay(5000);
|
||||
let windowHandles = await driver.getAllWindowHandles();
|
||||
const extension = windowHandles[0];
|
||||
const dapp = await driver.switchToWindowWithTitle(
|
||||
'E2E Test Dapp',
|
||||
windowHandles,
|
||||
);
|
||||
const popup = windowHandles.find(
|
||||
(handle) => handle !== extension && handle !== dapp,
|
||||
);
|
||||
await driver.switchToWindow(popup);
|
||||
await driver.clickElement({ text: 'Next', tag: 'button' });
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
|
||||
// creates a deploy contract transaction
|
||||
await driver.switchToWindow(dapp);
|
||||
await driver.clickElement('#deployButton');
|
||||
|
||||
// displays the contract creation data
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
@ -87,13 +68,15 @@ describe('Deploy contract and call contract methods', function () {
|
||||
await driver.switchToWindow(dapp);
|
||||
await driver.clickElement('#depositButton');
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
await driver.delay(5000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.delay(regularDelayMs);
|
||||
await driver.waitForSelector({
|
||||
css: '.confirm-page-container-summary__action__name',
|
||||
text: 'Deposit',
|
||||
});
|
||||
await driver.clickElement({ text: 'Confirm', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
await driver.switchToWindow(extension);
|
||||
@ -113,13 +96,15 @@ describe('Deploy contract and call contract methods', function () {
|
||||
await driver.switchToWindow(dapp);
|
||||
await driver.clickElement('#withdrawButton');
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
await driver.delay(5000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.delay(regularDelayMs);
|
||||
await driver.waitForSelector({
|
||||
css: '.confirm-page-container-summary__action__name',
|
||||
text: 'Withdraw',
|
||||
});
|
||||
await driver.clickElement({ text: 'Confirm', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
await driver.switchToWindow(extension);
|
||||
|
@ -16,7 +16,7 @@ describe('Failing contract interaction ', function () {
|
||||
await withFixtures(
|
||||
{
|
||||
dapp: true,
|
||||
fixtures: 'imported-account',
|
||||
fixtures: 'connected-state',
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
},
|
||||
@ -25,9 +25,9 @@ describe('Failing contract interaction ', function () {
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
|
||||
// connects the dapp
|
||||
// deploy contract
|
||||
await driver.openNewPage('http://127.0.0.1:8080/');
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.clickElement('#deployFailingButton');
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
let windowHandles = await driver.getAllWindowHandles();
|
||||
const extension = windowHandles[0];
|
||||
@ -35,19 +35,6 @@ describe('Failing contract interaction ', function () {
|
||||
'E2E Test Dapp',
|
||||
windowHandles,
|
||||
);
|
||||
const popup = windowHandles.find(
|
||||
(handle) => handle !== extension && handle !== dapp,
|
||||
);
|
||||
await driver.switchToWindow(popup);
|
||||
await driver.clickElement({ text: 'Next', tag: 'button' });
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
|
||||
// deploy contract
|
||||
await driver.switchToWindow(dapp);
|
||||
await driver.clickElement('#deployFailingButton');
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
|
@ -123,26 +123,12 @@ describe('Navigate transactions', function () {
|
||||
'second transaction in focus',
|
||||
);
|
||||
|
||||
// connects the dapp
|
||||
// add transaction
|
||||
await driver.openNewPage('http://127.0.0.1:8080/');
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.clickElement({ text: 'Send', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
const windowHandles = await driver.getAllWindowHandles();
|
||||
const extension = windowHandles[0];
|
||||
const dapp = await driver.switchToWindowWithTitle(
|
||||
'E2E Test Dapp',
|
||||
windowHandles,
|
||||
);
|
||||
const popup = windowHandles.find(
|
||||
(handle) => handle !== extension && handle !== dapp,
|
||||
);
|
||||
await driver.switchToWindow(popup);
|
||||
await driver.clickElement({ text: 'Next', tag: 'button' });
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
|
||||
// add transaction
|
||||
await driver.switchToWindow(dapp);
|
||||
await driver.clickElement({ text: 'Send', tag: 'button' });
|
||||
await driver.switchToWindow(extension);
|
||||
navigationElement = await driver.waitForSelector(
|
||||
{
|
||||
|
@ -41,7 +41,6 @@ describe('Phishing Detection', function () {
|
||||
await driver.navigate();
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
await driver.navigate();
|
||||
await driver.openNewPage('http://example.com');
|
||||
await driver.waitForSelector({ text: 'continuing at your own risk' });
|
||||
const header = await driver.findElement('h1');
|
||||
|
@ -1,9 +1,5 @@
|
||||
const { strict: assert } = require('assert');
|
||||
const {
|
||||
convertToHexValue,
|
||||
withFixtures,
|
||||
regularDelayMs,
|
||||
} = require('../helpers');
|
||||
const { convertToHexValue, withFixtures } = require('../helpers');
|
||||
|
||||
describe('Send ETH from inside MetaMask using default gas', function () {
|
||||
const ganacheOptions = {
|
||||
@ -47,7 +43,12 @@ describe('Send ETH from inside MetaMask using default gas', function () {
|
||||
await inputAmount.press(driver.Key.BACK_SPACE);
|
||||
await inputAmount.press(driver.Key.BACK_SPACE);
|
||||
await inputAmount.press(driver.Key.BACK_SPACE);
|
||||
await driver.delay(regularDelayMs);
|
||||
await driver.wait(async () => {
|
||||
const sendDialogMsgs = await driver.findElements(
|
||||
'.send-v2__form div.dialog',
|
||||
);
|
||||
return sendDialogMsgs.length === 1;
|
||||
}, 10000);
|
||||
|
||||
await driver.assertElementNotPresent('.send-v2__error-amount');
|
||||
|
||||
@ -158,10 +159,6 @@ describe('Send ETH from inside MetaMask using advanced gas modal', function () {
|
||||
});
|
||||
|
||||
describe('Send ETH from dapp using advanced gas controls', function () {
|
||||
let windowHandles;
|
||||
let extension;
|
||||
let popup;
|
||||
let dapp;
|
||||
const ganacheOptions = {
|
||||
accounts: [
|
||||
{
|
||||
@ -176,7 +173,7 @@ describe('Send ETH from dapp using advanced gas controls', function () {
|
||||
await withFixtures(
|
||||
{
|
||||
dapp: true,
|
||||
fixtures: 'imported-account',
|
||||
fixtures: 'connected-state',
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
},
|
||||
@ -200,52 +197,46 @@ describe('Send ETH from dapp using advanced gas controls', function () {
|
||||
await driver.clickElement(
|
||||
'[data-testid="advanced-setting-advanced-gas-inline"] .settings-page__content-item-col > label > div',
|
||||
);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
extension = windowHandles[0];
|
||||
await driver.closeAllWindowHandlesExcept([extension]);
|
||||
await driver.clickElement('.app-header__logo-container');
|
||||
|
||||
// connects the dapp
|
||||
await driver.openNewPage('http://127.0.0.1:8080/');
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
extension = windowHandles[0];
|
||||
dapp = await driver.switchToWindowWithTitle(
|
||||
'E2E Test Dapp',
|
||||
windowHandles,
|
||||
);
|
||||
popup = windowHandles.find(
|
||||
(handle) => handle !== extension && handle !== dapp,
|
||||
);
|
||||
await driver.switchToWindow(popup);
|
||||
await driver.clickElement({ text: 'Next', tag: 'button' });
|
||||
await driver.clickElement({ text: 'Connect', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
await driver.switchToWindow(dapp);
|
||||
|
||||
// initiates a send from the dapp
|
||||
await driver.openNewPage('http://127.0.0.1:8080/');
|
||||
await driver.clickElement({ text: 'Send', tag: 'button' });
|
||||
await driver.delay(2000);
|
||||
windowHandles = await driver.getAllWindowHandles();
|
||||
await driver.waitUntilXWindowHandles(3);
|
||||
const windowHandles = await driver.getAllWindowHandles();
|
||||
const extension = windowHandles[0];
|
||||
await driver.switchToWindowWithTitle(
|
||||
'MetaMask Notification',
|
||||
windowHandles,
|
||||
);
|
||||
await driver.assertElementNotPresent({ text: 'Data', tag: 'li' });
|
||||
await driver.clickElement({ text: 'Edit', tag: 'button' });
|
||||
await driver.delay(1000);
|
||||
await driver.waitForSelector({
|
||||
css: '.transaction-total-banner',
|
||||
text: '0.00021 ETH',
|
||||
});
|
||||
await driver.clickElement(
|
||||
{ text: 'Edit suggested gas fee', tag: 'button' },
|
||||
10000,
|
||||
);
|
||||
await driver.delay(1000);
|
||||
await driver.waitForSelector({
|
||||
css: '.transaction-total-banner',
|
||||
text: '0.00021 ETH',
|
||||
});
|
||||
const inputs = await driver.findElements('input[type="number"]');
|
||||
const gasPriceInput = inputs[1];
|
||||
await gasPriceInput.press(driver.Key.BACK_SPACE);
|
||||
await gasPriceInput.press(driver.Key.BACK_SPACE);
|
||||
await gasPriceInput.fill('100');
|
||||
await driver.delay(1000);
|
||||
await driver.waitForSelector({
|
||||
css: '.transaction-total-banner',
|
||||
text: '0.0021 ETH',
|
||||
});
|
||||
await driver.clickElement({ text: 'Save', tag: 'button' });
|
||||
await driver.delay(1000);
|
||||
await driver.waitForSelector({
|
||||
css: '.transaction-detail-item:nth-of-type(1) h6:nth-of-type(2)',
|
||||
text: '0.0021 ETH',
|
||||
});
|
||||
await driver.clickElement({ text: 'Confirm', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
await driver.switchToWindow(extension);
|
||||
|
@ -53,6 +53,7 @@ class Driver {
|
||||
this.Key = {
|
||||
BACK_SPACE: '\uE003',
|
||||
ENTER: '\uE007',
|
||||
SPACE: '\uE00D',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,10 @@ Object.assign(window, { fetch, Headers, Request, Response });
|
||||
window.localStorage = {
|
||||
removeItem: () => null,
|
||||
};
|
||||
|
||||
// used for native dark/light mode detection
|
||||
window.matchMedia = () => true;
|
||||
|
||||
// override @metamask/logo
|
||||
window.requestAnimationFrame = () => undefined;
|
||||
|
||||
|
@ -244,6 +244,7 @@ export const createSwapsMockStore = () => {
|
||||
fetchTime: 1354,
|
||||
aggregator: 'TEST_AGG_2',
|
||||
aggType: 'AGG',
|
||||
isBestQuote: true,
|
||||
slippage: 2,
|
||||
sourceTokenInfo: {
|
||||
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
|
@ -5,6 +5,7 @@ import Fuse from 'fuse.js';
|
||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||
import classnames from 'classnames';
|
||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||
import Identicon from '../../ui/identicon';
|
||||
import SiteIcon from '../../ui/site-icon';
|
||||
@ -197,7 +198,7 @@ export default class AccountMenu extends Component {
|
||||
className="account-menu__account account-menu__item--clickable"
|
||||
onClick={() => {
|
||||
this.context.trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Switched Account',
|
||||
properties: {
|
||||
action: 'Main Menu',
|
||||
@ -340,7 +341,7 @@ export default class AccountMenu extends Component {
|
||||
onClick={() => {
|
||||
toggleAccountMenu();
|
||||
trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Clicked Create Account',
|
||||
properties: {
|
||||
action: 'Main Menu',
|
||||
@ -356,7 +357,7 @@ export default class AccountMenu extends Component {
|
||||
onClick={() => {
|
||||
toggleAccountMenu();
|
||||
trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Clicked Import Account',
|
||||
properties: {
|
||||
action: 'Main Menu',
|
||||
@ -377,7 +378,7 @@ export default class AccountMenu extends Component {
|
||||
onClick={() => {
|
||||
toggleAccountMenu();
|
||||
trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Clicked Connect Hardware',
|
||||
properties: {
|
||||
action: 'Main Menu',
|
||||
@ -417,7 +418,7 @@ export default class AccountMenu extends Component {
|
||||
toggleAccountMenu();
|
||||
history.push(SETTINGS_ROUTE);
|
||||
this.context.trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Opened Settings',
|
||||
properties: {
|
||||
action: 'Main Menu',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import ActionableMessage from '../../ui/actionable-message';
|
||||
import Box from '../../ui/box';
|
||||
import Typography from '../../ui/typography';
|
||||
import {
|
||||
@ -10,10 +10,17 @@ import {
|
||||
COLORS,
|
||||
DISPLAY,
|
||||
FLEX_DIRECTION,
|
||||
FONT_WEIGHT,
|
||||
TYPOGRAPHY,
|
||||
JUSTIFY_CONTENT,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import Button from '../../ui/button';
|
||||
import IconCaretLeft from '../../ui/icon/icon-caret-left';
|
||||
import Tooltip from '../../ui/tooltip';
|
||||
import IconWithFallback from '../../ui/icon-with-fallback';
|
||||
import IconBorder from '../../ui/icon-border';
|
||||
import { getTheme } from '../../../selectors';
|
||||
import { THEME_TYPE } from '../../../pages/settings/experimental-tab/experimental-tab.constant';
|
||||
|
||||
const AddNetwork = ({
|
||||
onBackClick,
|
||||
@ -22,10 +29,13 @@ const AddNetwork = ({
|
||||
featuredRPCS,
|
||||
}) => {
|
||||
const t = useContext(I18nContext);
|
||||
const theme = useSelector(getTheme);
|
||||
|
||||
const infuraRegex = /infura.io/u;
|
||||
|
||||
const nets = featuredRPCS
|
||||
.sort((a, b) => (a.ticker > b.ticker ? 1 : -1))
|
||||
.slice(0, 5);
|
||||
.slice(0, 8);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@ -63,28 +73,73 @@ const AddNetwork = ({
|
||||
color={COLORS.TEXT_MUTED}
|
||||
margin={[4, 0, 3, 0]}
|
||||
>
|
||||
{t('customNetworks')}
|
||||
{t('popularCustomNetworks')}
|
||||
</Typography>
|
||||
{nets.map((item, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={ALIGN_ITEMS.CENTER}
|
||||
justifyContent={JUSTIFY_CONTENT.SPACE_BETWEEN}
|
||||
marginBottom={6}
|
||||
>
|
||||
<img
|
||||
className="add-network__token-image"
|
||||
src={item?.rpcPrefs?.imageUrl}
|
||||
alt={t('logo', [item.ticker])}
|
||||
/>
|
||||
<Typography variant={TYPOGRAPHY.H7} color={COLORS.TEXT_DEFAULT}>
|
||||
{item.ticker}
|
||||
</Typography>
|
||||
<i
|
||||
className="fa fa-plus add-network__add-icon"
|
||||
onClick={onAddNetworkClick}
|
||||
title={`${t('add')} ${item.ticker}`}
|
||||
/>
|
||||
<Box display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}>
|
||||
<IconBorder size={24}>
|
||||
<IconWithFallback
|
||||
icon={item.rpcPrefs.imageUrl}
|
||||
name={item.nickname}
|
||||
size={24}
|
||||
/>
|
||||
</IconBorder>
|
||||
<Typography
|
||||
variant={TYPOGRAPHY.H7}
|
||||
color={COLORS.TEXT_DEFAULT}
|
||||
fontWeight={FONT_WEIGHT.BOLD}
|
||||
boxProps={{ marginLeft: 2 }}
|
||||
>
|
||||
{item.nickname}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box display={DISPLAY.FLEX} alignItems={ALIGN_ITEMS.CENTER}>
|
||||
{
|
||||
// Warning for the networks that doesn't use infura.io as the RPC
|
||||
!infuraRegex.test(item.rpcUrl) && (
|
||||
<Tooltip
|
||||
className="add-network__warning-tooltip"
|
||||
position="top"
|
||||
interactive
|
||||
html={
|
||||
<Box margin={3} className="add-network__warning-tooltip">
|
||||
{t('addNetworkTooltipWarning', [
|
||||
<a
|
||||
key="zendesk_page_link"
|
||||
href="https://metamask.zendesk.com/hc/en-us/articles/4417500466971"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{t('learnMoreUpperCase')}
|
||||
</a>,
|
||||
])}
|
||||
</Box>
|
||||
}
|
||||
trigger="mouseenter"
|
||||
theme={theme === THEME_TYPE.DEFAULT ? 'light' : 'dark'}
|
||||
>
|
||||
<i
|
||||
className="fa fa-exclamation-triangle add-network__warning-icon"
|
||||
title={t('warning')}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
<Button
|
||||
type="inline"
|
||||
className="add-network__add-button"
|
||||
onClick={onAddNetworkClick}
|
||||
>
|
||||
{t('add')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
@ -98,25 +153,6 @@ const AddNetwork = ({
|
||||
{t('addANetworkManually')}
|
||||
</Typography>
|
||||
</Button>
|
||||
<ActionableMessage
|
||||
type="warning"
|
||||
message={
|
||||
<>
|
||||
{t('onlyInteractWith')}
|
||||
<a
|
||||
href="https://metamask.zendesk.com/hc/en-us/articles/4417500466971"
|
||||
target="_blank"
|
||||
className="add-network__footer__link"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t('endOfFlowMessage9')}
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
iconFillColor="var(--color-warning-default)"
|
||||
useIcon
|
||||
withRightButton
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
@ -1,9 +1,12 @@
|
||||
import React from 'react';
|
||||
import AddNetwork from '.';
|
||||
import AddNetwork from './add-network';
|
||||
|
||||
const MATIC_TOKEN_IMAGE_URL = './images/matic-token.png';
|
||||
const ARBITRUM_IMAGE_URL = './images/arbitrum.svg';
|
||||
const OPTIMISM_IMAGE_URL = './images/optimism.svg';
|
||||
const AVALANCHE_IMAGE_URL = './images/avax-token.png';
|
||||
const PALM_IMAGE_URL = './images/palm.svg';
|
||||
const BSC_IMAGE_URL = './images/bsc-filled.svg';
|
||||
|
||||
export default {
|
||||
title: 'Components/APP/AddNetwork',
|
||||
@ -25,36 +28,83 @@ export default {
|
||||
args: {
|
||||
featuredRPCS: [
|
||||
{
|
||||
chainId: '0x89',
|
||||
nickname: 'Polygon Mumbai',
|
||||
rpcUrl:
|
||||
'https://polygon-mainnet.infura.io/v3/2b6d4a83d89a438eb1b5d036788ab29c',
|
||||
ticker: 'MATIC',
|
||||
chainId: '42161',
|
||||
nickname: 'Arbitrum One',
|
||||
rpcUrl: 'https://arbitrum-mainnet.infura.io/v3/{INFURA_API_KEY}',
|
||||
ticker: 'AETH',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://mumbai.polygonscan.com/',
|
||||
imageUrl: MATIC_TOKEN_IMAGE_URL,
|
||||
blockExplorerUrl: 'https://explorer.arbitrum.io',
|
||||
imageUrl: ARBITRUM_IMAGE_URL,
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '0x99',
|
||||
nickname: 'Optimism Testnet ',
|
||||
rpcUrl:
|
||||
'https://optimism-kovan.infura.io/v3/2b6d4a83d89a438eb1b5d036788ab29c',
|
||||
chainId: '43114',
|
||||
nickname: 'Avalanche Mainnet C-Chain',
|
||||
rpcUrl: 'https://api.avax.network/ext/bc/C/rpc',
|
||||
ticker: 'AVAX',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://snowtrace.io/',
|
||||
imageUrl: AVALANCHE_IMAGE_URL,
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '56',
|
||||
nickname: 'BNB Smart Chain',
|
||||
rpcUrl: 'https://bsc-dataseed.binance.org/',
|
||||
ticker: 'BNB',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://bscscan.com/',
|
||||
imageUrl: BSC_IMAGE_URL,
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '250',
|
||||
nickname: 'Fantom Opera',
|
||||
rpcUrl: 'https://rpc.ftm.tools/',
|
||||
ticker: 'FTM',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://ftmscan.com/',
|
||||
imageUrl: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '1666600000',
|
||||
nickname: 'Harmony Mainnet Shard 0',
|
||||
rpcUrl: 'https://api.harmony.one/',
|
||||
ticker: 'ONE',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://explorer.harmony.one/',
|
||||
imageUrl: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '10',
|
||||
nickname: 'Optimism',
|
||||
rpcUrl: 'https://optimism-mainnet.infura.io/v3/{INFURA_API_KEY}',
|
||||
ticker: 'KOR',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://kovan-optimistic.etherscan.io/',
|
||||
blockExplorerUrl: 'https://optimistic.etherscan.io/',
|
||||
imageUrl: OPTIMISM_IMAGE_URL,
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '0x66eeb',
|
||||
nickname: 'Arbitrum Testnet',
|
||||
rpcUrl:
|
||||
'https://arbitrum-rinkeby.infura.io/v3/2b6d4a83d89a438eb1b5d036788ab29c',
|
||||
ticker: 'ARETH',
|
||||
chainId: '137',
|
||||
nickname: 'Polygon Mainnet',
|
||||
rpcUrl: 'https://polygon-mainnet.infura.io/v3/{INFURA_API_KEY}',
|
||||
ticker: 'MATIC',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://testnet.arbiscan.io/',
|
||||
imageUrl: ARBITRUM_IMAGE_URL,
|
||||
blockExplorerUrl: 'https://polygonscan.com/',
|
||||
imageUrl: MATIC_TOKEN_IMAGE_URL,
|
||||
},
|
||||
},
|
||||
{
|
||||
chainId: '11297108109',
|
||||
nickname: 'Palm',
|
||||
rpcUrl: 'https://palm-mainnet.infura.io/v3/{INFURA_API_KEY}',
|
||||
ticker: 'PALM',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://explorer.palm.io/',
|
||||
imageUrl: PALM_IMAGE_URL,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -8,10 +8,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__token-image {
|
||||
margin-right: 7px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
&__warning-icon {
|
||||
color: var(--color-icon-muted);
|
||||
}
|
||||
|
||||
&__warning-tooltip {
|
||||
color: var(--color-text-alternative);
|
||||
width: 180px;
|
||||
|
||||
a {
|
||||
color: var(--color-primary-default);
|
||||
}
|
||||
}
|
||||
|
||||
&__add-icon {
|
||||
@ -21,6 +28,12 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__add-button.button {
|
||||
color: var(--color-primary-default);
|
||||
font-size: $font-size-h7;
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
border-top: 1px solid var(--color-border-muted);
|
||||
|
||||
@ -39,3 +52,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@ import classnames from 'classnames';
|
||||
import Identicon from '../../ui/identicon';
|
||||
import MetaFoxLogo from '../../ui/metafox-logo';
|
||||
import { DEFAULT_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import NetworkDisplay from '../network-display';
|
||||
|
||||
export default class AppHeader extends PureComponent {
|
||||
@ -45,7 +46,7 @@ export default class AppHeader extends PureComponent {
|
||||
|
||||
if (networkDropdownOpen === false) {
|
||||
this.context.trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Opened Network Menu',
|
||||
properties: {
|
||||
action: 'Home',
|
||||
@ -77,7 +78,7 @@ export default class AppHeader extends PureComponent {
|
||||
if (!disabled) {
|
||||
!isAccountMenuOpen &&
|
||||
this.context.trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Opened Main Menu',
|
||||
properties: {
|
||||
action: 'Home',
|
||||
|
@ -13,6 +13,7 @@ import { updateSendAsset } from '../../../ducks/send';
|
||||
import { SEND_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { SEVERITIES } from '../../../helpers/constants/design-system';
|
||||
import { INVALID_ASSET_TYPE } from '../../../helpers/constants/error-keys';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { ASSET_TYPES } from '../../../../shared/constants/transaction';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
|
||||
@ -65,7 +66,7 @@ const AssetListItem = ({
|
||||
e.stopPropagation();
|
||||
trackEvent({
|
||||
event: 'Clicked Send: Token',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Home',
|
||||
legacy_event: true,
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
|
||||
const AssetList = ({ onClickAsset }) => {
|
||||
const t = useI18nContext();
|
||||
@ -83,7 +84,7 @@ const AssetList = ({ onClickAsset }) => {
|
||||
onClickAsset(tokenAddress);
|
||||
trackEvent({
|
||||
event: 'Clicked Token',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Token Menu',
|
||||
legacy_event: true,
|
||||
@ -107,7 +108,7 @@ const AssetList = ({ onClickAsset }) => {
|
||||
history.push(IMPORT_TOKEN_ROUTE);
|
||||
trackEvent({
|
||||
event: 'Clicked "Add Token"',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Token Menu',
|
||||
legacy_event: true,
|
||||
|
@ -13,6 +13,7 @@ import InfoTooltip from '../../../../ui/info-tooltip';
|
||||
import NicknamePopovers from '../../../modals/nickname-popovers';
|
||||
import Typography from '../../../../ui/typography';
|
||||
import { TYPOGRAPHY } from '../../../../../helpers/constants/design-system';
|
||||
import { ORIGIN_METAMASK } from '../../../../../../shared/constants/app';
|
||||
|
||||
const ConfirmPageContainerSummary = (props) => {
|
||||
const {
|
||||
@ -83,7 +84,7 @@ const ConfirmPageContainerSummary = (props) => {
|
||||
|
||||
return (
|
||||
<div className={classnames('confirm-page-container-summary', className)}>
|
||||
{origin === 'metamask' ? null : (
|
||||
{origin === ORIGIN_METAMASK ? null : (
|
||||
<div className="confirm-page-container-summary__origin">{origin}</div>
|
||||
)}
|
||||
<div className="confirm-page-container-summary__action-row">
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useContext, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import TextField from '../../ui/text-field';
|
||||
@ -83,7 +84,7 @@ export default function CreateNewVault({
|
||||
|
||||
const toggleTermsCheck = useCallback(() => {
|
||||
trackEvent({
|
||||
category: 'Onboarding',
|
||||
category: EVENT.CATEGORIES.ONBOARDING,
|
||||
event: 'Check ToS',
|
||||
properties: {
|
||||
action: 'Import Seed Phrase',
|
||||
|
@ -17,6 +17,7 @@ import { COLORS, SIZES } from '../../../helpers/constants/design-system';
|
||||
import { getShowTestNetworks } from '../../../selectors';
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import {
|
||||
ADD_NETWORK_ROUTE,
|
||||
ADVANCED_ROUTE,
|
||||
@ -110,7 +111,7 @@ class NetworkDropdown extends Component {
|
||||
const { trackEvent } = this.context;
|
||||
|
||||
trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Switched Networks',
|
||||
properties: {
|
||||
action: 'Home',
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
GAS_ESTIMATE_TYPES,
|
||||
CUSTOM_GAS_ESTIMATE,
|
||||
} from '../../../../shared/constants/gas';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
|
||||
import Button from '../../ui/button';
|
||||
import Typography from '../../ui/typography/typography';
|
||||
@ -280,7 +281,7 @@ export default function EditGasDisplay({
|
||||
setShowAdvancedForm(!showAdvancedForm);
|
||||
trackEvent({
|
||||
event: 'Clicked "Advanced Options"',
|
||||
category: 'Transactions',
|
||||
category: EVENT.CATEGORIES.TRANSACTIONS,
|
||||
properties: {
|
||||
action: 'Edit Screen',
|
||||
legacy_event: true,
|
||||
|
@ -86,6 +86,8 @@ export default function ExperimentalArea({ redirectTo }) {
|
||||
<p>{t('flaskWelcomeWarning2')}</p>
|
||||
<br />
|
||||
<p>{t('flaskWelcomeWarning3')}</p>
|
||||
<br />
|
||||
<p>{t('flaskWelcomeWarning4')}</p>
|
||||
</div>
|
||||
<Button type="primary" onClick={onClick}>
|
||||
{t('flaskWelcomeWarningAcceptButton')}
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
addPollingTokenToAppState,
|
||||
removePollingTokenFromAppState,
|
||||
} from '../../../../store/actions';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
import AdvancedTabContent from './advanced-tab-content';
|
||||
import BasicTabContent from './basic-tab-content';
|
||||
|
||||
@ -219,7 +220,7 @@ export default class GasModalPageContainer extends Component {
|
||||
onSubmit={() => {
|
||||
if (isSpeedUp) {
|
||||
this.context.trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Saved "Speed Up"',
|
||||
properties: {
|
||||
action: 'Activity Log',
|
||||
|
@ -8,6 +8,7 @@ import Box from '../../ui/box/box';
|
||||
import { TEXT_ALIGN } from '../../../helpers/constants/design-system';
|
||||
import { detectNewTokens } from '../../../store/actions';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
|
||||
export default function ImportTokenLink({ isMainnet }) {
|
||||
const trackEvent = useContext(MetaMetricsContext);
|
||||
@ -35,7 +36,7 @@ export default function ImportTokenLink({ isMainnet }) {
|
||||
history.push(IMPORT_TOKEN_ROUTE);
|
||||
trackEvent({
|
||||
event: 'Clicked "Add Token"',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Token Menu',
|
||||
legacy_event: true,
|
||||
|
@ -17,6 +17,7 @@ import {
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
|
||||
export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
@ -46,7 +47,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
onClick={() => {
|
||||
trackEvent({
|
||||
event: 'Clicked Block Explorer Link',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
link_type: 'Account Tracker',
|
||||
action: 'Account Options',
|
||||
@ -76,7 +77,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
onClick={() => {
|
||||
trackEvent({
|
||||
event: 'Clicked Expand View',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Account Options',
|
||||
legacy_event: true,
|
||||
@ -96,7 +97,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
dispatch(showModal({ name: 'ACCOUNT_DETAILS' }));
|
||||
trackEvent({
|
||||
event: 'Viewed Account Details',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Account Options',
|
||||
legacy_event: true,
|
||||
@ -113,7 +114,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
onClick={() => {
|
||||
trackEvent({
|
||||
event: 'Opened Connected Sites',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Account Options',
|
||||
legacy_event: true,
|
||||
|
@ -6,6 +6,7 @@ import SelectedAccount from '../selected-account';
|
||||
import ConnectedStatusIndicator from '../connected-status-indicator';
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
||||
import { EVENT } from '../../../../shared/constants/metametrics';
|
||||
import { CONNECTED_ACCOUNTS_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { getOriginOfCurrentTab } from '../../../selectors';
|
||||
@ -46,7 +47,7 @@ export default function MenuBar() {
|
||||
onClick={() => {
|
||||
trackEvent({
|
||||
event: 'Opened Account Options',
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
properties: {
|
||||
action: 'Home',
|
||||
legacy_event: true,
|
||||
|
@ -8,6 +8,7 @@ import Box from '../../ui/box';
|
||||
import MetaMaskTranslation from '../metamask-translation';
|
||||
import NetworkDisplay from '../network-display';
|
||||
import TextArea from '../../ui/textarea/textarea';
|
||||
import ConfirmationNetworkSwitch from '../../../pages/confirmation/components/confirmation-network-switch';
|
||||
|
||||
export const safeComponentList = {
|
||||
MetaMaskTranslation,
|
||||
@ -25,4 +26,5 @@ export const safeComponentList = {
|
||||
Box,
|
||||
NetworkDisplay,
|
||||
TextArea,
|
||||
ConfirmationNetworkSwitch,
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ import EditableLabel from '../../../ui/editable-label';
|
||||
import Button from '../../../ui/button';
|
||||
import { getURLHostName } from '../../../../helpers/utils/util';
|
||||
import { isHardwareKeyring } from '../../../../helpers/utils/hardware';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
|
||||
export default class AccountDetailsModal extends Component {
|
||||
static propTypes = {
|
||||
@ -76,7 +77,7 @@ export default class AccountDetailsModal extends Component {
|
||||
onClick={() => {
|
||||
const accountLink = getAccountLink(address, chainId, rpcPrefs);
|
||||
this.context.trackEvent({
|
||||
category: 'Navigation',
|
||||
category: EVENT.CATEGORIES.NAVIGATION,
|
||||
event: 'Clicked Block Explorer Link',
|
||||
properties: {
|
||||
link_type: 'Account Tracker',
|
||||
|
@ -4,6 +4,7 @@ import { getAccountLink } from '@metamask/etherscan-link';
|
||||
import Modal from '../../modal';
|
||||
import { addressSummary, getURLHostName } from '../../../../helpers/utils/util';
|
||||
import Identicon from '../../../ui/identicon';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
|
||||
export default class ConfirmRemoveAccount extends Component {
|
||||
static propTypes = {
|
||||
@ -60,7 +61,7 @@ export default class ConfirmRemoveAccount extends Component {
|
||||
rpcPrefs,
|
||||
);
|
||||
this.context.trackEvent({
|
||||
category: 'Accounts',
|
||||
category: EVENT.CATEGORIES.ACCOUNTS,
|
||||
event: 'Clicked Block Explorer Link',
|
||||
properties: {
|
||||
link_type: 'Account Tracker',
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
NETWORK_TO_NAME_MAP,
|
||||
BUYABLE_CHAINS_MAP,
|
||||
} from '../../../../../shared/constants/network';
|
||||
import { EVENT } from '../../../../../shared/constants/metametrics';
|
||||
import Button from '../../../ui/button';
|
||||
import LogoMoonPay from '../../../ui/logo/logo-moonpay';
|
||||
import LogoWyre from '../../../ui/logo/logo-wyre';
|
||||
@ -137,7 +138,7 @@ export default class DepositEtherModal extends Component {
|
||||
buttonLabel: t('continueToTransak'),
|
||||
onButtonClick: () => {
|
||||
this.context.trackEvent({
|
||||
category: 'Accounts',
|
||||
category: EVENT.CATEGORIES.ACCOUNTS,
|
||||
event: 'Click buy Ether via Transak',
|
||||
properties: {
|
||||
action: 'Deposit Ether',
|
||||
@ -155,7 +156,7 @@ export default class DepositEtherModal extends Component {
|
||||
buttonLabel: t('continueToMoonPay'),
|
||||
onButtonClick: () => {
|
||||
this.context.trackEvent({
|
||||
category: 'Accounts',
|
||||
category: EVENT.CATEGORIES.ACCOUNTS,
|
||||
event: 'Click buy Ether via MoonPay',
|
||||
properties: {
|
||||
action: 'Deposit Ether',
|
||||
@ -173,7 +174,7 @@ export default class DepositEtherModal extends Component {
|
||||
buttonLabel: t('continueToWyre'),
|
||||
onButtonClick: () => {
|
||||
this.context.trackEvent({
|
||||
category: 'Accounts',
|
||||
category: EVENT.CATEGORIES.ACCOUNTS,
|
||||
event: 'Click buy Ether via Wyre',
|
||||
properties: {
|
||||
action: 'Deposit Ether',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user