diff --git a/.circleci/config.yml b/.circleci/config.yml index 207593689..ec7b51d1c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -195,7 +195,7 @@ jobs: - build-artifacts validate-lavamoat-config: - executor: node-browsers + executor: node-browsers-medium-plus steps: - checkout - attach_workspace: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..f945eb7b7 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ develop, Version-v*, cla-signatures, master, snaps ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ develop ] + schedule: + - cron: '28 12 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # πŸ“š https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.prettierignore b/.prettierignore index 67bd43f64..2e0417ca7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,5 @@ node_modules/** -lavamoat/*/policy.json +lavamoat/**/policy.json dist/** builds/** test-*/** diff --git a/CHANGELOG.md b/CHANGELOG.md index 95c6dbee3..e1547c7ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.7.0] +### Changed +- [#12643](https://github.com/MetaMask/metamask-extension/pull/12643): Reject popup confirmations on close +- [#12566](https://github.com/MetaMask/metamask-extension/pull/12566): Enable LavaMoat for the webapp background +- [#12399](https://github.com/MetaMask/metamask-extension/pull/12399): Update the "Account Details" view + - Change "Close" icon color from gray -> black + - Display the entire account address + - Use rounded style for "View on Etherscan" and "Export Private Key" buttons +- [#12824](https://github.com/MetaMask/metamask-extension/pull/12824): Add multilayer fee to token approval screen + +### Fixed +- [#12696](https://github.com/MetaMask/metamask-extension/pull/12696): Show correct base asset for current network in the Signature Request view +- [#12727](https://github.com/MetaMask/metamask-extension/pull/12727): Make toggle buttons keyboard accessible +- [#12729](https://github.com/MetaMask/metamask-extension/pull/12729): Swaps: Fix issue with wrapping and unwrapping when an address contains uppercase characters +- [#12631](https://github.com/MetaMask/metamask-extension/pull/12631): Fix bug preventing sending high precision decimal amounts of tokens in the send flow + ## [10.6.4] ### Changed - [#12752](https://github.com/MetaMask/metamask-extension/pull/12752): Update link, in the add network flow, to the article with information about network security risks @@ -170,7 +186,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#11967](https://github.com/MetaMask/metamask-extension/pull/11967): Fix the display of long contact names on the contact settings pages. - [#12122](https://github.com/MetaMask/metamask-extension/pull/12122): Ensure failed speedups don't prevent further speedup attempts, and hide the Base Fee and Priority Fee fields when we don't have that information - [#11963](https://github.com/MetaMask/metamask-extension/pull/11963): Show scrollbar in the accounts menu - - This makes the accounts list scrollable for users with no mouse scroll wheel. + - This makes the accounts list scrollable for users with no mouse scroll wheel. - [#12058](https://github.com/MetaMask/metamask-extension/pull/12058): Fix clipping issue with long network names in the network dropdown - [#12039](https://github.com/MetaMask/metamask-extension/pull/12039): Add missing padding at the bottom of the custom network form in the popup view - [#11890](https://github.com/MetaMask/metamask-extension/pull/11890): Fix alignment of horizontal line shown under gas recommendations @@ -182,7 +198,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#12144](https://github.com/MetaMask/metamask-extension/pull/12144): Add What's New notification about ledger EIP-1559 support and firmware updates ### Fixed -- [#12069](https://github.com/MetaMask/metamask-extension/pull/12069): Fixes bug where suggestedGasFee api is called excessively. +- [#12069](https://github.com/MetaMask/metamask-extension/pull/12069): Fixes bug where suggestedGasFee api is called excessively. ## [10.1.0] ### Added @@ -337,7 +353,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#11118](https://github.com/MetaMask/metamask-extension/pull/11118): Removing support survey notification from What's New - [#11115](https://github.com/MetaMask/metamask-extension/pull/11115): Hide basic tab in advanced gas modal for speedup and cancel when on testnets - [#11030](https://github.com/MetaMask/metamask-extension/pull/11030): Return a specific error (code 4902) for switchEthereumChain requests for chains that aren't already in the user's wallet. -- [#11093](https://github.com/MetaMask/metamask-extension/pull/11093): Update all uses of "Seed Phrase" to "Secret Recovery Phrase" +- [#11093](https://github.com/MetaMask/metamask-extension/pull/11093): Update all uses of "Seed Phrase" to "Secret Recovery Phrase" ### Fixed - [#11025](https://github.com/MetaMask/metamask-extension/pull/11025): Fixed redirection to the build quotes page from the swaps page when failure has occured @@ -357,14 +373,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Re-added "Add Ledger Live Support" ([#10293](https://github.com/MetaMask/metamask-extension/pull/10293)), which was reverted in the previous version ### Fixed -- [#11225](https://github.com/MetaMask/metamask-extension/pull/11225) - Fix persistent display of chrome ledger What's New popup message +- [#11225](https://github.com/MetaMask/metamask-extension/pull/11225) - Fix persistent display of chrome ledger What's New popup message ## [9.5.8] ### Added - Re-added "Add Ledger Live Support" ([#10293](https://github.com/MetaMask/metamask-extension/pull/10293)), which was reverted in the previous version ### Fixed -- [#11207](https://github.com/MetaMask/metamask-extension/pull/11207) - Fix error causing crashes on some locales on v9.5.6 +- [#11207](https://github.com/MetaMask/metamask-extension/pull/11207) - Fix error causing crashes on some locales on v9.5.6 ## [9.5.7] ### Fixed @@ -2613,7 +2629,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Uncategorized - Added the ability to restore accounts from seed words. -[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.6.4...HEAD +[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.7.0...HEAD +[10.7.0]: https://github.com/MetaMask/metamask-extension/compare/v10.6.4...v10.7.0 [10.6.4]: https://github.com/MetaMask/metamask-extension/compare/v10.6.3...v10.6.4 [10.6.3]: https://github.com/MetaMask/metamask-extension/compare/v10.6.2...v10.6.3 [10.6.2]: https://github.com/MetaMask/metamask-extension/compare/v10.6.1...v10.6.2 diff --git a/README.md b/README.md index 9ab7dcb60..4045873cf 100644 --- a/README.md +++ b/README.md @@ -67,9 +67,17 @@ Whenever you change dependencies (adding, removing, or updating, either in `pack * The `allow-scripts` configuration in `package.json` * Run `yarn allow-scripts auto` to update the `allow-scripts` configuration automatically. This config determines whether the package's install/postinstall scripts are allowed to run. Review each new package to determine whether the install script needs to run or not, testing if necessary. * Unfortunately, `yarn allow-scripts auto` will behave inconsistently on different platforms. macOS and Windows users may see extraneous changes relating to optional dependencies. -* The LavaMoat auto-generated policy in `lavamoat/node/policy.json` - * Run `yarn lavamoat:auto` to re-generate this policy file. Review the changes to determine whether the access granted to each package seems appropriate. - * Unfortunately, `yarn lavamoat:auto` will behave inconsistently on different platforms. macOS and Windows users may see extraneous changes relating to optional dependencies. +* The LavaMoat policy files. The _tl;dr_ is to run `yarn lavamoat:auto` to update these files, but there can be devils in the details. Continue reading for more information. + * There are two sets of LavaMoat policy files: + * The production LavaMoat policy files (`lavamoat/browserify/*/policy.json`), which are re-generated using `yarn lavamoat:background:auto`. + * These should be regenerated whenever the production dependencies for the background change. + * The build system LavaMoat policy file (`lavamoat/build-system/policy.json`), which is re-generated using `yarn lavamoat:build:auto`. + * This should be regenerated whenever the dependencies used by the build system itself change. + * Whenever you regenerate a policy file, review the changes to determine whether the access granted to each package seems appropriate. + * Unfortunately, `yarn lavamoat:auto` will behave inconsistently on different platforms. + macOS and Windows users may see extraneous changes relating to optional dependencies. + * Keep in mind that any kind of dynamic import or dynamic use of globals may elude LavaMoat's static analysis. + Refer to the LavaMoat documentation or ask for help if you run into any issues. ## Architecture diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 59f67b50d..b3cbda168 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -43,6 +43,9 @@ "activityLog": { "message": "activity log" }, + "add": { + "message": "Add" + }, "addANetwork": { "message": "Add a network" }, @@ -100,6 +103,9 @@ "addToken": { "message": "Add Token" }, + "address": { + "message": "Address" + }, "addressBookIcon": { "message": "Address book icon" }, @@ -167,6 +173,14 @@ "message": "MetaMask", "description": "The name of the application" }, + "appNameBeta": { + "message": "MetaMask Beta", + "description": "The name of the application (Beta)" + }, + "appNameFlask": { + "message": "MetaMask Flask", + "description": "The name of the application (Flask)" + }, "approvalAndAggregatorTxFeeCost": { "message": "Approval and aggregator network fee" }, @@ -549,6 +563,9 @@ "currentlyUnavailable": { "message": "Unavailable on this network" }, + "custom": { + "message": "Advanced" + }, "customGas": { "message": "Customize Gas" }, @@ -561,6 +578,13 @@ "customToken": { "message": "Custom Token" }, + "dappSuggested": { + "message": "Site suggested" + }, + "dappSuggestedTooltip": { + "message": "$1 has recommended this price.", + "description": "$1 represents the Dapp's origin" + }, "data": { "message": "Data" }, @@ -891,6 +915,9 @@ "etherscanView": { "message": "View account on Etherscan" }, + "etherscanViewOn": { + "message": "View on Etherscan" + }, "expandView": { "message": "Expand view" }, @@ -1002,6 +1029,9 @@ "gasPriceInfoTooltipContent": { "message": "Gas price specifies the amount of Ether you are willing to pay for each unit of gas." }, + "gasPriceLabel": { + "message": "Gas price" + }, "gasTimingMinutes": { "message": "$1 minutes", "description": "$1 represents a number of minutes" @@ -1100,9 +1130,15 @@ "hideZeroBalanceTokens": { "message": "Hide Tokens Without Balance" }, + "high": { + "message": "Aggressive" + }, "history": { "message": "History" }, + "id": { + "message": "ID" + }, "import": { "message": "Import", "description": "Button to import an account from a selected file" @@ -1117,7 +1153,7 @@ "message": "import using Secret Recovery Phrase" }, "importAccountMsg": { - "message": " Imported accounts will not be associated with your originally created MetaMask account Secret Recovery Phrase. Learn more about imported accounts " + "message": "Imported accounts will not be associated with your originally created MetaMask account Secret Recovery Phrase. Learn more about imported accounts" }, "importAccountSeedPhrase": { "message": "Import a wallet with Secret Recovery Phrase" @@ -1336,6 +1372,12 @@ "lockTimeTooGreat": { "message": "Lock time is too great" }, + "low": { + "message": "Low" + }, + "lowPriorityMessage": { + "message": "Future transactions will queue after this one. This price was last seen was some time ago." + }, "mainnet": { "message": "Ethereum Mainnet" }, @@ -1349,12 +1391,18 @@ "max": { "message": "Max" }, + "maxBaseFee": { + "message": "Max base fee" + }, "maxFee": { "message": "Max fee" }, "maxPriorityFee": { "message": "Max priority fee" }, + "medium": { + "message": "Market" + }, "memo": { "message": "memo" }, @@ -1560,6 +1608,9 @@ "message": "Nonce is higher than suggested nonce of $1", "description": "The next nonce according to MetaMask's internal logic" }, + "nftTokenIdPlaceholder": { + "message": "Enter the collectible ID" + }, "nfts": { "message": "NFTs" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 3f054b244..8555b89a4 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -503,7 +503,7 @@ "message": "编辑权限" }, "encryptionPublicKeyNotice": { - "message": "$1 εΈŒζœ›εΎ—εˆ°ζ‚¨ηš„εŠ ε―†ε…¬ι’₯γ€‚εŒζ„εŽθ―₯网站将可δ»₯ζƒ³ζ‚¨ε‘ι€εŠ ε―†δΏ‘ζ―γ€‚", + "message": "$1 εΈŒζœ›εΎ—εˆ°ζ‚¨ηš„εŠ ε―†ε…¬ι’₯γ€‚εŒζ„εŽθ―₯网站将可δ»₯ε‘ζ‚¨ε‘ι€εŠ ε―†δΏ‘ζ―γ€‚", "description": "$1 is the web3 site name" }, "encryptionPublicKeyRequest": { diff --git a/app/build-types/beta/manifest/_base.json b/app/build-types/beta/manifest/_base.json index 33a2da321..bfdb451ed 100644 --- a/app/build-types/beta/manifest/_base.json +++ b/app/build-types/beta/manifest/_base.json @@ -21,6 +21,6 @@ "128": "images/icon-128.png", "512": "images/icon-512.png" }, - "name": "__MSG_appName__ Beta", - "short_name": "__MSG_appName__ Beta" + "name": "__MSG_appNameBeta__", + "short_name": "__MSG_appNameBeta__" } diff --git a/app/build-types/flask/manifest/_base.json b/app/build-types/flask/manifest/_base.json index d9c8ec220..bc43d646a 100644 --- a/app/build-types/flask/manifest/_base.json +++ b/app/build-types/flask/manifest/_base.json @@ -21,6 +21,6 @@ "128": "images/icon-128.png", "512": "images/icon-512.png" }, - "name": "__MSG_appName__ Flask", - "short_name": "__MSG_appName__ Flask" + "name": "__MSG_appNameFlask__", + "short_name": "__MSG_appNameFlask__" } diff --git a/app/scripts/background.js b/app/scripts/background.js index d8d99150f..ed546dc26 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -17,13 +17,19 @@ import { ENVIRONMENT_TYPE_FULLSCREEN, } from '../../shared/constants/app'; import { SECOND } from '../../shared/constants/time'; +import { + REJECT_NOTFICIATION_CLOSE, + REJECT_NOTFICIATION_CLOSE_SIG, +} from '../../shared/constants/metametrics'; import migrations from './migrations'; import Migrator from './lib/migrator'; import ExtensionPlatform from './platforms/extension'; import LocalStore from './lib/local-store'; import ReadOnlyNetworkStore from './lib/network-store'; import createStreamSink from './lib/createStreamSink'; -import NotificationManager from './lib/notification-manager'; +import NotificationManager, { + NOTIFICATION_MANAGER_EVENTS, +} from './lib/notification-manager'; import MetamaskController, { METAMASK_CONTROLLER_EVENTS, } from './metamask-controller'; @@ -475,6 +481,69 @@ function setupController(initState, initLangCode) { extension.browserAction.setBadgeBackgroundColor({ color: '#037DD6' }); } + notificationManager.on( + NOTIFICATION_MANAGER_EVENTS.POPUP_CLOSED, + rejectUnapprovedNotifications, + ); + + function rejectUnapprovedNotifications() { + Object.keys( + controller.txController.txStateManager.getUnapprovedTxList(), + ).forEach((txId) => + controller.txController.txStateManager.setTxStatusRejected(txId), + ); + controller.messageManager.messages + .filter((msg) => msg.status === 'unapproved') + .forEach((tx) => + controller.messageManager.rejectMsg( + tx.id, + REJECT_NOTFICIATION_CLOSE_SIG, + ), + ); + controller.personalMessageManager.messages + .filter((msg) => msg.status === 'unapproved') + .forEach((tx) => + controller.personalMessageManager.rejectMsg( + tx.id, + REJECT_NOTFICIATION_CLOSE_SIG, + ), + ); + controller.typedMessageManager.messages + .filter((msg) => msg.status === 'unapproved') + .forEach((tx) => + controller.typedMessageManager.rejectMsg( + tx.id, + REJECT_NOTFICIATION_CLOSE_SIG, + ), + ); + controller.decryptMessageManager.messages + .filter((msg) => msg.status === 'unapproved') + .forEach((tx) => + controller.decryptMessageManager.rejectMsg( + tx.id, + REJECT_NOTFICIATION_CLOSE, + ), + ); + controller.encryptionPublicKeyManager.messages + .filter((msg) => msg.status === 'unapproved') + .forEach((tx) => + controller.encryptionPublicKeyManager.rejectMsg( + tx.id, + REJECT_NOTFICIATION_CLOSE, + ), + ); + + // We're specifcally avoid using approvalController directly for better + // Error support during rejection + Object.keys( + controller.permissionsController.approvals.state.pendingApprovals, + ).forEach((approvalId) => + controller.permissionsController.rejectPermissionsRequest(approvalId), + ); + + updateBadge(); + } + return Promise.resolve(); } diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 772a9ebde..ff143bff8 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,10 +1,13 @@ import { createScaffoldMiddleware, mergeMiddleware } from 'json-rpc-engine'; -import createBlockRefMiddleware from 'eth-json-rpc-middleware/block-ref'; -import createRetryOnEmptyMiddleware from 'eth-json-rpc-middleware/retryOnEmpty'; -import createBlockCacheMiddleware from 'eth-json-rpc-middleware/block-cache'; -import createInflightCacheMiddleware from 'eth-json-rpc-middleware/inflight-cache'; -import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector'; -import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware'; +import { + createBlockRefMiddleware, + createRetryOnEmptyMiddleware, + createBlockCacheMiddleware, + createInflightCacheMiddleware, + createBlockTrackerInspectorMiddleware, + providerFromMiddleware, +} from 'eth-json-rpc-middleware'; + import createInfuraMiddleware from 'eth-json-rpc-infura'; import { PollingBlockTracker } from 'eth-block-tracker'; diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index 050430740..f4ca59157 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -1,10 +1,12 @@ import { createAsyncMiddleware, mergeMiddleware } from 'json-rpc-engine'; -import createFetchMiddleware from 'eth-json-rpc-middleware/fetch'; -import createBlockRefRewriteMiddleware from 'eth-json-rpc-middleware/block-ref-rewrite'; -import createBlockCacheMiddleware from 'eth-json-rpc-middleware/block-cache'; -import createInflightMiddleware from 'eth-json-rpc-middleware/inflight-cache'; -import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector'; -import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware'; +import { + createFetchMiddleware, + createBlockRefRewriteMiddleware, + createBlockCacheMiddleware, + createInflightCacheMiddleware, + createBlockTrackerInspectorMiddleware, + providerFromMiddleware, +} from 'eth-json-rpc-middleware'; import { PollingBlockTracker } from 'eth-block-tracker'; import { SECOND } from '../../../../shared/constants/time'; @@ -27,7 +29,7 @@ export default function createJsonRpcClient({ rpcUrl, chainId }) { createChainIdMiddleware(chainId), createBlockRefRewriteMiddleware({ blockTracker }), createBlockCacheMiddleware({ blockTracker }), - createInflightMiddleware(), + createInflightCacheMiddleware(), createBlockTrackerInspectorMiddleware({ blockTracker }), fetchMiddleware, ]); diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index c3803a061..cee6b9b95 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -1,5 +1,5 @@ import { createScaffoldMiddleware, mergeMiddleware } from 'json-rpc-engine'; -import createWalletSubprovider from 'eth-json-rpc-middleware/wallet'; +import { createWalletMiddleware } from 'eth-json-rpc-middleware'; import { createPendingNonceMiddleware, createPendingTxMiddleware, @@ -21,11 +21,10 @@ export default function createMetamaskMiddleware({ }) { const metamaskMiddleware = mergeMiddleware([ createScaffoldMiddleware({ - // staticSubprovider eth_syncing: false, web3_clientVersion: `MetaMask/v${version}`, }), - createWalletSubprovider({ + createWalletMiddleware({ getAccounts, processTransaction, processEthSignMessage, diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 543649d35..9423c6a80 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -2,7 +2,7 @@ import { strict as assert } from 'assert'; import EventEmitter from 'events'; import { ComposedStore, ObservableStore } from '@metamask/obs-store'; import { JsonRpcEngine } from 'json-rpc-engine'; -import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine'; +import { providerFromEngine } from 'eth-json-rpc-middleware'; import log from 'loglevel'; import { createSwappableProxy, @@ -430,7 +430,7 @@ export default class NetworkController extends EventEmitter { } _setProviderAndBlockTracker({ provider, blockTracker }) { - // update or intialize proxies + // update or initialize proxies if (this._providerProxy) { this._providerProxy.setTarget(provider); } else { diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index d67d4efe5..a53cf8993 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -37,6 +37,7 @@ export default class PreferencesController { // set to true means the dynamic list from the API is being used // set to false will be using the static list from contract-metadata useTokenDetection: false, + advancedGasFee: null, // WARNING: Do not use feature flags for security-sensitive things. // Feature flag toggling is available in the global namespace @@ -129,6 +130,16 @@ export default class PreferencesController { this.store.updateState({ useTokenDetection: val }); } + /** + * Setter for the `advancedGasFee` property + * + * @param {object} val - holds the maxBaseFee and PriorityFee that the user set as default advanced settings. + * + */ + setAdvancedGasFee(val) { + this.store.updateState({ advancedGasFee: val }); + } + /** * Add new methodData to state, to avoid requesting this information again through Infura * diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index 51277bce2..bce64e1a9 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -266,4 +266,28 @@ describe('preferences controller', function () { ); }); }); + + describe('setAdvancedGasFee', function () { + it('should default to null', function () { + const state = preferencesController.store.getState(); + assert.equal(state.advancedGasFee, null); + }); + + it('should set the setAdvancedGasFee property in state', function () { + const state = preferencesController.store.getState(); + assert.equal(state.advancedGasFee, null); + preferencesController.setAdvancedGasFee({ + maxBaseFee: '1.5', + priorityFee: '2', + }); + assert.equal( + preferencesController.store.getState().advancedGasFee.maxBaseFee, + '1.5', + ); + assert.equal( + preferencesController.store.getState().advancedGasFee.priorityFee, + '2', + ); + }); + }); }); diff --git a/app/scripts/controllers/swaps.js b/app/scripts/controllers/swaps.js index d57558fcc..397883b72 100644 --- a/app/scripts/controllers/swaps.js +++ b/app/scripts/controllers/swaps.js @@ -281,7 +281,7 @@ export default class SwapsController { // For a user to be able to swap a token, they need to have approved the MetaSwap contract to withdraw that token. // _getERC20Allowance() returns the amount of the token they have approved for withdrawal. If that amount is greater - // than 0, it means that approval has already occured and is not needed. Otherwise, for tokens to be swapped, a new + // than 0, it means that approval has already occurred and is not needed. Otherwise, for tokens to be swapped, a new // call of the ERC-20 approve method is required. approvalRequired = allowance.eq(0) && diff --git a/app/scripts/controllers/threebox.js b/app/scripts/controllers/threebox.js index 10b231b38..fc278d0b2 100644 --- a/app/scripts/controllers/threebox.js +++ b/app/scripts/controllers/threebox.js @@ -8,7 +8,7 @@ const Box = process.env.IN_TEST import log from 'loglevel'; import { JsonRpcEngine } from 'json-rpc-engine'; -import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine'; +import { providerFromEngine } from 'eth-json-rpc-middleware'; import Migrator from '../lib/migrator'; import migrations from '../migrations'; import createOriginMiddleware from '../lib/createOriginMiddleware'; diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 74eacc396..0f1d15961 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -26,6 +26,7 @@ import { TRANSACTION_TYPES, TRANSACTION_ENVELOPE_TYPES, } from '../../../../shared/constants/transaction'; +import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions'; import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller'; import { GAS_LIMITS, @@ -1447,8 +1448,8 @@ export default class TransactionController extends EventEmitter { sensitiveProperties: { status, transaction_envelope_type: isEIP1559Transaction(txMeta) - ? 'fee-market' - : 'legacy', + ? TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET + : TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY, first_seen: time, gas_limit: gasLimit, ...gasParamsInGwei, diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index dbf7ca9d8..c2f7a344b 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -20,6 +20,7 @@ import { GAS_ESTIMATE_TYPES, GAS_RECOMMENDATIONS, } from '../../../../shared/constants/gas'; +import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions'; import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller'; import TransactionController, { TRANSACTION_EVENTS } from '.'; @@ -774,7 +775,7 @@ describe('Transaction Controller', function () { nonce: '0x4b', }, type: TRANSACTION_TYPES.SIMPLE_SEND, - transaction_envelope_type: 'legacy', + transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY, origin: 'metamask', chainId: currentChainId, time: 1624408066355, @@ -1578,7 +1579,7 @@ describe('Transaction Controller', function () { gas_price: '2', gas_limit: '0x7b0d', first_seen: 1624408066355, - transaction_envelope_type: 'legacy', + transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY, status: 'unapproved', }, }; @@ -1625,7 +1626,7 @@ describe('Transaction Controller', function () { gas_price: '2', gas_limit: '0x7b0d', first_seen: 1624408066355, - transaction_envelope_type: 'legacy', + transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY, status: 'unapproved', }, }; @@ -1674,7 +1675,7 @@ describe('Transaction Controller', function () { gas_price: '2', gas_limit: '0x7b0d', first_seen: 1624408066355, - transaction_envelope_type: 'legacy', + transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY, status: 'unapproved', }, }; @@ -1731,7 +1732,7 @@ describe('Transaction Controller', function () { max_priority_fee_per_gas: '2', gas_limit: '0x7b0d', first_seen: 1624408066355, - transaction_envelope_type: 'fee-market', + transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET, status: 'unapproved', estimate_suggested: GAS_RECOMMENDATIONS.MEDIUM, estimate_used: GAS_RECOMMENDATIONS.HIGH, diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js index f9f15e33b..bda772693 100644 --- a/app/scripts/lib/buy-eth-url.js +++ b/app/scripts/lib/buy-eth-url.js @@ -1,12 +1,13 @@ import log from 'loglevel'; -import { METASWAP_CHAINID_API_HOST_MAP } from '../../../shared/constants/swaps'; +import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps'; import { GOERLI_CHAIN_ID, KOVAN_CHAIN_ID, MAINNET_CHAIN_ID, RINKEBY_CHAIN_ID, ROPSTEN_CHAIN_ID, + MAINNET_NETWORK_ID, } from '../../../shared/constants/network'; import { SECOND } from '../../../shared/constants/time'; import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'; @@ -20,7 +21,7 @@ const fetchWithTimeout = getFetchWithTimeout(SECOND * 30); * @returns String */ const createWyrePurchaseUrl = async (address) => { - const fiatOnRampUrlApi = `${METASWAP_CHAINID_API_HOST_MAP[MAINNET_CHAIN_ID]}/fiatOnRampUrl?serviceName=wyre&destinationAddress=${address}`; + const fiatOnRampUrlApi = `${SWAPS_API_V2_BASE_URL}/networks/${MAINNET_NETWORK_ID}/fiatOnRampUrl?serviceName=wyre&destinationAddress=${address}`; const wyrePurchaseUrlFallback = `https://pay.sendwyre.com/purchase?dest=ethereum:${address}&destCurrency=ETH&accountId=AC-7AG3W4XH4N2&paymentMethod=debit-card`; try { const response = await fetchWithTimeout(fiatOnRampUrlApi, { diff --git a/app/scripts/lib/buy-eth-url.test.js b/app/scripts/lib/buy-eth-url.test.js index d15af3e5d..b240f55b8 100644 --- a/app/scripts/lib/buy-eth-url.test.js +++ b/app/scripts/lib/buy-eth-url.test.js @@ -7,6 +7,7 @@ import { ROPSTEN_CHAIN_ID, } from '../../../shared/constants/network'; import { TRANSAK_API_KEY } from '../constants/on-ramp'; +import { SWAPS_API_V2_BASE_URL } from '../../../shared/constants/swaps'; import getBuyEthUrl from './buy-eth-url'; const WYRE_ACCOUNT_ID = 'AC-7AG3W4XH4N2'; @@ -28,8 +29,10 @@ const KOVAN = { describe('buy-eth-url', function () { it('returns Wyre url with an ETH address for Ethereum mainnet', async function () { - nock('https://api.metaswap.codefi.network') - .get(`/fiatOnRampUrl?serviceName=wyre&destinationAddress=${ETH_ADDRESS}`) + nock(SWAPS_API_V2_BASE_URL) + .get( + `/networks/1/fiatOnRampUrl?serviceName=wyre&destinationAddress=${ETH_ADDRESS}`, + ) .reply(200, { url: `https://pay.sendwyre.com/purchase?accountId=${WYRE_ACCOUNT_ID}&utm_campaign=${WYRE_ACCOUNT_ID}&destCurrency=ETH&utm_medium=widget&paymentMethod=debit-card&reservation=MLZVUF8FMXZUMARJC23B&dest=ethereum%3A${ETH_ADDRESS}&utm_source=checkout`, }); diff --git a/app/scripts/lib/decrypt-message-manager.js b/app/scripts/lib/decrypt-message-manager.js index 56eabf552..534f4b62a 100644 --- a/app/scripts/lib/decrypt-message-manager.js +++ b/app/scripts/lib/decrypt-message-manager.js @@ -38,13 +38,14 @@ export default class DecryptMessageManager extends EventEmitter { * @property {Array} messages Holds all messages that have been created by this DecryptMessageManager * */ - constructor() { + constructor(opts) { super(); this.memStore = new ObservableStore({ unapprovedDecryptMsgs: {}, unapprovedDecryptMsgCount: 0, }); this.messages = []; + this.metricsEvent = opts.metricsEvent; } /** @@ -237,7 +238,16 @@ export default class DecryptMessageManager extends EventEmitter { * @param {number} msgId The id of the DecryptMessage to reject. * */ - rejectMsg(msgId) { + rejectMsg(msgId, reason = undefined) { + if (reason) { + this.metricsEvent({ + event: reason, + category: 'Messages', + properties: { + action: 'Decrypt Message Request', + }, + }); + } this._setMsgStatus(msgId, 'rejected'); } diff --git a/app/scripts/lib/encryption-public-key-manager.js b/app/scripts/lib/encryption-public-key-manager.js index 2a4b2296e..a6aead82c 100644 --- a/app/scripts/lib/encryption-public-key-manager.js +++ b/app/scripts/lib/encryption-public-key-manager.js @@ -34,13 +34,14 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @property {Array} messages Holds all messages that have been created by this EncryptionPublicKeyManager * */ - constructor() { + constructor(opts) { super(); this.memStore = new ObservableStore({ unapprovedEncryptionPublicKeyMsgs: {}, unapprovedEncryptionPublicKeyMsgCount: 0, }); this.messages = []; + this.metricsEvent = opts.metricsEvent; } /** @@ -226,7 +227,16 @@ export default class EncryptionPublicKeyManager extends EventEmitter { * @param {number} msgId The id of the EncryptionPublicKey to reject. * */ - rejectMsg(msgId) { + rejectMsg(msgId, reason = undefined) { + if (reason) { + this.metricsEvent({ + event: reason, + category: 'Messages', + properties: { + action: 'Encryption public key Request', + }, + }); + } this._setMsgStatus(msgId, 'rejected'); } diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index bb7756b33..0a83a2214 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -35,13 +35,14 @@ export default class MessageManager extends EventEmitter { * @property {Array} messages Holds all messages that have been created by this MessageManager * */ - constructor() { + constructor({ metricsEvent }) { super(); this.memStore = new ObservableStore({ unapprovedMsgs: {}, unapprovedMsgCount: 0, }); this.messages = []; + this.metricsEvent = metricsEvent; } /** @@ -217,7 +218,18 @@ export default class MessageManager extends EventEmitter { * @param {number} msgId - The id of the Message to reject. * */ - rejectMsg(msgId) { + rejectMsg(msgId, reason = undefined) { + if (reason) { + const msg = this.getMsg(msgId); + this.metricsEvent({ + event: reason, + category: 'Transactions', + properties: { + action: 'Sign Request', + type: msg.type, + }, + }); + } this._setMsgStatus(msgId, 'rejected'); } diff --git a/app/scripts/lib/message-manager.test.js b/app/scripts/lib/message-manager.test.js index 39183fb7a..82fa147b3 100644 --- a/app/scripts/lib/message-manager.test.js +++ b/app/scripts/lib/message-manager.test.js @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import sinon from 'sinon'; import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction'; import MessageManager from './message-manager'; @@ -6,7 +7,9 @@ describe('Message Manager', function () { let messageManager; beforeEach(function () { - messageManager = new MessageManager(); + messageManager = new MessageManager({ + metricsEvent: sinon.fake(), + }); }); describe('#getMsgList', function () { diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index d7a7a89e0..f07871211 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -1,9 +1,14 @@ +import EventEmitter from 'safe-event-emitter'; import ExtensionPlatform from '../platforms/extension'; const NOTIFICATION_HEIGHT = 620; const NOTIFICATION_WIDTH = 360; -export default class NotificationManager { +export const NOTIFICATION_MANAGER_EVENTS = { + POPUP_CLOSED: 'onPopupClosed', +}; + +export default class NotificationManager extends EventEmitter { /** * A collection of methods for controlling the showing and hiding of the notification popup. * @@ -12,7 +17,9 @@ export default class NotificationManager { */ constructor() { + super(); this.platform = new ExtensionPlatform(); + this.platform.addOnRemovedListener(this._onWindowClosed.bind(this)); } /** @@ -62,6 +69,13 @@ export default class NotificationManager { } } + _onWindowClosed(windowId) { + if (windowId === this._popupId) { + this._popupId = undefined; + this.emit(NOTIFICATION_MANAGER_EVENTS.POPUP_CLOSED); + } + } + /** * Checks all open MetaMask windows, and returns the first one it finds that is a notification window (i.e. has the * type 'popup') diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index 6002b0709..907f3ee5a 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -40,13 +40,14 @@ export default class PersonalMessageManager extends EventEmitter { * @property {Array} messages Holds all messages that have been created by this PersonalMessageManager * */ - constructor() { + constructor({ metricsEvent }) { super(); this.memStore = new ObservableStore({ unapprovedPersonalMsgs: {}, unapprovedPersonalMsgCount: 0, }); this.messages = []; + this.metricsEvent = metricsEvent; } /** @@ -238,7 +239,18 @@ export default class PersonalMessageManager extends EventEmitter { * @param {number} msgId - The id of the PersonalMessage to reject. * */ - rejectMsg(msgId) { + rejectMsg(msgId, reason = undefined) { + if (reason) { + const msg = this.getMsg(msgId); + this.metricsEvent({ + event: reason, + category: 'Transactions', + properties: { + action: 'Sign Request', + type: msg.type, + }, + }); + } this._setMsgStatus(msgId, 'rejected'); } diff --git a/app/scripts/lib/personal-message-manager.test.js b/app/scripts/lib/personal-message-manager.test.js index de241fff0..add3ac28e 100644 --- a/app/scripts/lib/personal-message-manager.test.js +++ b/app/scripts/lib/personal-message-manager.test.js @@ -1,4 +1,5 @@ import { strict as assert } from 'assert'; +import sinon from 'sinon'; import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction'; import PersonalMessageManager from './personal-message-manager'; @@ -6,7 +7,7 @@ describe('Personal Message Manager', function () { let messageManager; beforeEach(function () { - messageManager = new PersonalMessageManager(); + messageManager = new PersonalMessageManager({ metricsEvent: sinon.fake() }); }); describe('#getMsgList', function () { diff --git a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js index ea2370217..9c7935d3e 100644 --- a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js +++ b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js @@ -1,8 +1,10 @@ +import { ethErrors } from 'eth-rpc-errors'; +import { UNSUPPORTED_RPC_METHODS } from '../../../../shared/constants/network'; import handlers from './handlers'; const handlerMap = handlers.reduce((map, handler) => { for (const methodName of handler.methodNames) { - map.set(methodName, handler.implementation); + map.set(methodName, handler); } return map; }, new Map()); @@ -21,14 +23,41 @@ const handlerMap = handlers.reduce((map, handler) => { * Eventually, we'll want to extract this middleware into its own package. * * @param {Object} opts - The middleware options - * @param {Function} opts.sendMetrics - A function for sending a metrics event * @returns {(req: Object, res: Object, next: Function, end: Function) => void} */ export default function createMethodMiddleware(opts) { return function methodMiddleware(req, res, next, end) { - if (handlerMap.has(req.method)) { - return handlerMap.get(req.method)(req, res, next, end, opts); + // Reject unsupported methods. + if (UNSUPPORTED_RPC_METHODS.has(req.method)) { + return end(ethErrors.rpc.methodNotSupported()); } + + const handler = handlerMap.get(req.method); + if (handler) { + const { implementation, hookNames } = handler; + return implementation(req, res, next, end, selectHooks(opts, hookNames)); + } + return next(); }; } + +/** + * Returns the subset of the specified `hooks` that are included in the + * `hookNames` object. This is a Principle of Least Authority (POLA) measure + * to ensure that each RPC method implementation only has access to the + * API "hooks" it needs to do its job. + * + * @param {Record} hooks - The hooks to select from. + * @param {Record} hookNames - The names of the hooks to select. + * @returns {Record | undefined} The selected hooks. + */ +function selectHooks(hooks, hookNames) { + if (hookNames) { + return Object.keys(hookNames).reduce((hookSubset, hookName) => { + hookSubset[hookName] = hooks[hookName]; + return hookSubset; + }, {}); + } + return undefined; +} diff --git a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js index 50399c3ab..c6a85c2fb 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js @@ -12,6 +12,14 @@ import { CHAIN_ID_TO_NETWORK_ID_MAP } from '../../../../../shared/constants/netw const addEthereumChain = { methodNames: [MESSAGE_TYPE.ADD_ETHEREUM_CHAIN], implementation: addEthereumChainHandler, + hookNames: { + addCustomRpc: true, + getCurrentChainId: true, + findCustomRpcBy: true, + updateRpcTarget: true, + requestUserApproval: true, + sendMetrics: true, + }, }; export default addEthereumChain; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js index c38933b0d..afc09666a 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js @@ -9,6 +9,9 @@ import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; const getProviderState = { methodNames: [MESSAGE_TYPE.GET_PROVIDER_STATE], implementation: getProviderStateHandler, + hookNames: { + getProviderState: true, + }, }; export default getProviderState; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js b/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js index 973d03f61..8793cdf20 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js @@ -10,6 +10,11 @@ import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; const logWeb3ShimUsage = { methodNames: [MESSAGE_TYPE.LOG_WEB3_SHIM_USAGE], implementation: logWeb3ShimUsageHandler, + hookNames: { + sendMetrics: true, + getWeb3ShimUsageState: true, + setWeb3ShimUsageRecorded: true, + }, }; export default logWeb3ShimUsage; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js index d1e3d3a22..c2d73f16b 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js @@ -15,6 +15,13 @@ import { const switchEthereumChain = { methodNames: [MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN], implementation: switchEthereumChainHandler, + hookNames: { + getCurrentChainId: true, + findCustomRpcBy: true, + setProviderType: true, + updateRpcTarget: true, + requestUserApproval: true, + }, }; export default switchEthereumChain; diff --git a/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js b/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js index 95408eee3..a9fb503d9 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js @@ -3,6 +3,9 @@ import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; const watchAsset = { methodNames: [MESSAGE_TYPE.WATCH_ASSET, MESSAGE_TYPE.WATCH_ASSET_LEGACY], implementation: watchAssetHandler, + hookNames: { + handleWatchAssetRequest: true, + }, }; export default watchAsset; diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index 534ecf818..4d972fdf0 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -32,7 +32,7 @@ export default class TypedMessageManager extends EventEmitter { /** * Controller in charge of managing - storing, adding, removing, updating - TypedMessage. */ - constructor({ getCurrentChainId }) { + constructor({ getCurrentChainId, metricEvents }) { super(); this._getCurrentChainId = getCurrentChainId; this.memStore = new ObservableStore({ @@ -40,6 +40,7 @@ export default class TypedMessageManager extends EventEmitter { unapprovedTypedMessagesCount: 0, }); this.messages = []; + this.metricEvents = metricEvents; } /** @@ -301,7 +302,19 @@ export default class TypedMessageManager extends EventEmitter { * @param {number} msgId - The id of the TypedMessage to reject. * */ - rejectMsg(msgId) { + rejectMsg(msgId, reason = undefined) { + if (reason) { + const msg = this.getMsg(msgId); + this.metricsEvent({ + event: reason, + category: 'Transactions', + properties: { + action: 'Sign Request', + version: msg.msgParams.version, + type: msg.type, + }, + }); + } this._setMsgStatus(msgId, 'rejected'); } diff --git a/app/scripts/lib/typed-message-manager.test.js b/app/scripts/lib/typed-message-manager.test.js index a9722211e..ce70011ce 100644 --- a/app/scripts/lib/typed-message-manager.test.js +++ b/app/scripts/lib/typed-message-manager.test.js @@ -17,6 +17,7 @@ describe('Typed Message Manager', function () { beforeEach(async function () { typedMessageManager = new TypedMessageManager({ getCurrentChainId: sinon.fake.returns('0x1'), + metricsEvent: sinon.fake(), }); msgParamsV1 = { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 563ef40ed..e92640540 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -7,7 +7,7 @@ import { debounce } from 'lodash'; import createEngineStream from 'json-rpc-middleware-stream/engineStream'; import createFilterMiddleware from 'eth-json-rpc-filters'; import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; -import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware'; +import { providerAsMiddleware } from 'eth-json-rpc-middleware'; import KeyringController from 'eth-keyring-controller'; import { Mutex } from 'await-semaphore'; import { stripHexPrefix } from 'ethereumjs-util'; @@ -526,14 +526,33 @@ export default class MetamaskController extends EventEmitter { } }); this.networkController.lookupNetwork(); - this.messageManager = new MessageManager(); - this.personalMessageManager = new PersonalMessageManager(); - this.decryptMessageManager = new DecryptMessageManager(); - this.encryptionPublicKeyManager = new EncryptionPublicKeyManager(); + this.messageManager = new MessageManager({ + metricsEvent: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), + }); + this.personalMessageManager = new PersonalMessageManager({ + metricsEvent: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), + }); + this.decryptMessageManager = new DecryptMessageManager({ + metricsEvent: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), + }); + this.encryptionPublicKeyManager = new EncryptionPublicKeyManager({ + metricsEvent: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), + }); this.typedMessageManager = new TypedMessageManager({ getCurrentChainId: this.networkController.getCurrentChainId.bind( this.networkController, ), + metricsEvent: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), }); this.swapsController = new SwapsController({ @@ -924,6 +943,10 @@ export default class MetamaskController extends EventEmitter { this.preferencesController.setDismissSeedBackUpReminder, this.preferencesController, ), + setAdvancedGasFee: nodeify( + preferencesController.setAdvancedGasFee, + preferencesController, + ), // AddressController setAddressBook: nodeify( diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 4f7705a95..c2f931b49 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -162,6 +162,10 @@ export default class ExtensionPlatform { } } + addOnRemovedListener(listener) { + extension.windows.onRemoved.addListener(listener); + } + getAllWindows() { return new Promise((resolve, reject) => { extension.windows.getAll((windows) => { diff --git a/development/build/README.md b/development/build/README.md index 1218308c9..7d6cd8d9c 100644 --- a/development/build/README.md +++ b/development/build/README.md @@ -52,6 +52,9 @@ Options: bundle. Setting this to `false` is useful e.g. when linking dependencies that are incompatible with lockdown. [boolean] [default: true] + --policy-only Stops the build after generating the LavaMoat policy, + skipping any writes to disk. + [boolean] [deafult: false] --skip-stats Whether to refrain from logging build progress. Mostly used internally. [boolean] [default: false] diff --git a/development/build/index.js b/development/build/index.js index 7ee92f672..669cf6826 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -52,6 +52,7 @@ function defineAndRunBuildTasks() { buildType, entryTask, isLavaMoat, + policyOnly, shouldIncludeLockdown, shouldLintFenceFiles, skipStats, @@ -84,6 +85,7 @@ function defineAndRunBuildTasks() { ignoredFiles, isLavaMoat, livereload, + policyOnly, shouldLintFenceFiles, }); @@ -134,6 +136,9 @@ function defineAndRunBuildTasks() { ), ); + // build just production scripts, for LavaMoat policy generation purposes + createTask('scripts:prod', scriptTasks.prod); + // build for CI testing createTask( 'test', @@ -157,6 +162,7 @@ function parseArgv() { BuildType: 'build-type', LintFenceFiles: 'lint-fence-files', Lockdown: 'lockdown', + PolicyOnly: 'policy-only', SkipStats: 'skip-stats', }; @@ -164,6 +170,7 @@ function parseArgv() { boolean: [ NamedArgs.LintFenceFiles, NamedArgs.Lockdown, + NamedArgs.PolicyOnly, NamedArgs.SkipStats, ], string: [NamedArgs.BuildType], @@ -171,6 +178,7 @@ function parseArgv() { [NamedArgs.BuildType]: BuildType.main, [NamedArgs.LintFenceFiles]: true, [NamedArgs.Lockdown]: true, + [NamedArgs.PolicyOnly]: false, [NamedArgs.SkipStats]: false, }, }); @@ -198,10 +206,13 @@ function parseArgv() { ? argv[NamedArgs.LintFenceFiles] : !/dev/iu.test(entryTask); + const policyOnly = argv[NamedArgs.PolicyOnly]; + return { buildType, entryTask, isLavaMoat: process.argv[0].includes('lavamoat'), + policyOnly, shouldIncludeLockdown: argv[NamedArgs.Lockdown], shouldLintFenceFiles, skipStats: argv[NamedArgs.SkipStats], diff --git a/development/build/scripts.js b/development/build/scripts.js index cc916cf68..cf49dd302 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -134,6 +134,10 @@ function getSegmentWriteKey({ buildType, environment }) { throw new Error(`Invalid build type: '${buildType}'`); } +const noopWriteStream = through.obj((_file, _fileEncoding, callback) => + callback(), +); + module.exports = createScriptTasks; function createScriptTasks({ @@ -143,6 +147,7 @@ function createScriptTasks({ isLavaMoat, livereload, shouldLintFenceFiles, + policyOnly, }) { // internal tasks const core = { @@ -185,6 +190,7 @@ function createScriptTasks({ return `./app/scripts/${label}.js`; }), ignoredFiles, + policyOnly, shouldLintFenceFiles, testing, }), @@ -200,18 +206,18 @@ function createScriptTasks({ // this can run whenever const disableConsoleSubtask = createTask( `${taskPrefix}:disable-console`, - createTaskForBundleDisableConsole({ devMode }), + createTaskForBundleDisableConsole({ devMode, testing }), ); // this can run whenever const installSentrySubtask = createTask( `${taskPrefix}:sentry`, - createTaskForBundleSentry({ devMode }), + createTaskForBundleSentry({ devMode, testing }), ); const phishingDetectSubtask = createTask( `${taskPrefix}:phishing-detect`, - createTaskForBundlePhishingDetect({ devMode }), + createTaskForBundlePhishingDetect({ devMode, testing }), ); // task for initiating browser livereload @@ -241,6 +247,7 @@ function createScriptTasks({ runInChildProcess(subtask, { buildType, isLavaMoat, + policyOnly, shouldLintFenceFiles, }), ); @@ -248,7 +255,7 @@ function createScriptTasks({ return composeParallel(initiateLiveReload, ...allSubtasks); } - function createTaskForBundleDisableConsole({ devMode }) { + function createTaskForBundleDisableConsole({ devMode, testing }) { const label = 'disable-console'; return createNormalBundle({ browserPlatforms, @@ -258,11 +265,13 @@ function createScriptTasks({ entryFilepath: `./app/scripts/${label}.js`, ignoredFiles, label, + testing, + policyOnly, shouldLintFenceFiles, }); } - function createTaskForBundleSentry({ devMode }) { + function createTaskForBundleSentry({ devMode, testing }) { const label = 'sentry-install'; return createNormalBundle({ browserPlatforms, @@ -272,11 +281,13 @@ function createScriptTasks({ entryFilepath: `./app/scripts/${label}.js`, ignoredFiles, label, + testing, + policyOnly, shouldLintFenceFiles, }); } - function createTaskForBundlePhishingDetect({ devMode }) { + function createTaskForBundlePhishingDetect({ devMode, testing }) { const label = 'phishing-detect'; return createNormalBundle({ buildType, @@ -286,6 +297,8 @@ function createScriptTasks({ entryFilepath: `./app/scripts/${label}.js`, ignoredFiles, label, + testing, + policyOnly, shouldLintFenceFiles, }); } @@ -303,6 +316,7 @@ function createScriptTasks({ entryFilepath: `./app/scripts/${inpage}.js`, label: inpage, ignoredFiles, + policyOnly, shouldLintFenceFiles, testing, }), @@ -314,6 +328,7 @@ function createScriptTasks({ entryFilepath: `./app/scripts/${contentscript}.js`, label: contentscript, ignoredFiles, + policyOnly, shouldLintFenceFiles, testing, }), @@ -327,6 +342,7 @@ function createFactoredBuild({ devMode, entryFiles, ignoredFiles, + policyOnly, shouldLintFenceFiles, testing, }) { @@ -346,6 +362,7 @@ function createFactoredBuild({ devMode, envVars, ignoredFiles, + policyOnly, minify, reloadOnChange, shouldLintFenceFiles, @@ -358,10 +375,14 @@ function createFactoredBuild({ // lavamoat will add lavapack but it will be removed by bify-module-groups // we will re-add it later by installing a lavapack runtime const lavamoatOpts = { - policy: path.resolve(__dirname, '../../lavamoat/browserify/policy.json'), + policy: path.resolve( + __dirname, + `../../lavamoat/browserify/${buildType}/policy.json`, + ), + policyName: buildType, policyOverride: path.resolve( __dirname, - '../../lavamoat/browserify/policy-override.json', + `../../lavamoat/browserify/${buildType}/policy-override.json`, ), writeAutoPolicy: process.env.WRITE_AUTO_POLICY, }; @@ -413,12 +434,17 @@ function createFactoredBuild({ // setup bundle destination browserPlatforms.forEach((platform) => { const dest = `./dist/${platform}/`; - pipeline.get('dest').push(gulp.dest(dest)); + const destination = policyOnly ? noopWriteStream : gulp.dest(dest); + pipeline.get('dest').push(destination); }); }); // wait for bundle completion for postprocessing events.on('bundleDone', () => { + // Skip HTML generation if nothing is to be written to disk + if (policyOnly) { + return; + } const commonSet = sizeGroupMap.get('common'); // create entry points for each file for (const [groupLabel, groupSet] of sizeGroupMap.entries()) { @@ -456,7 +482,7 @@ function createFactoredBuild({ groupSet, commonSet, browserPlatforms, - useLavamoat: false, + useLavamoat: true, }); break; } @@ -492,6 +518,7 @@ function createNormalBundle({ extraEntries = [], ignoredFiles, label, + policyOnly, modulesToExpose, shouldLintFenceFiles, testing, @@ -512,6 +539,7 @@ function createNormalBundle({ devMode, envVars, ignoredFiles, + policyOnly, minify, reloadOnChange, shouldLintFenceFiles, @@ -536,7 +564,8 @@ function createNormalBundle({ // setup bundle destination browserPlatforms.forEach((platform) => { const dest = `./dist/${platform}/`; - pipeline.get('dest').push(gulp.dest(dest)); + const destination = policyOnly ? noopWriteStream : gulp.dest(dest); + pipeline.get('dest').push(destination); }); }); @@ -566,6 +595,7 @@ function setupBundlerDefaults( devMode, envVars, ignoredFiles, + policyOnly, minify, reloadOnChange, shouldLintFenceFiles, @@ -609,12 +639,14 @@ function setupBundlerDefaults( setupReloadOnChange(buildConfiguration); } - if (minify) { - setupMinification(buildConfiguration); - } + if (!policyOnly) { + if (minify) { + setupMinification(buildConfiguration); + } - // Setup source maps - setupSourcemaps(buildConfiguration, { devMode }); + // Setup source maps + setupSourcemaps(buildConfiguration, { devMode }); + } } function setupReloadOnChange({ bundlerOpts, events }) { diff --git a/development/build/task.js b/development/build/task.js index 07cd6d0c3..316020259 100644 --- a/development/build/task.js +++ b/development/build/task.js @@ -50,7 +50,7 @@ function createTask(taskName, taskFn) { function runInChildProcess( task, - { buildType, isLavaMoat, shouldLintFenceFiles }, + { buildType, isLavaMoat, policyOnly, shouldLintFenceFiles }, ) { const taskName = typeof task === 'string' ? task : task.taskName; if (!taskName) { @@ -74,6 +74,7 @@ function runInChildProcess( '--lint-fence-files', shouldLintFenceFiles, '--skip-stats', + ...(policyOnly ? ['--policy-only'] : []), ], { env: process.env, @@ -90,6 +91,7 @@ function runInChildProcess( '--lint-fence-files', shouldLintFenceFiles, '--skip-stats', + ...(policyOnly ? ['--policy-only'] : []), ], { env: process.env, diff --git a/development/generate-lavamoat-policies.sh b/development/generate-lavamoat-policies.sh new file mode 100755 index 000000000..a5a104a23 --- /dev/null +++ b/development/generate-lavamoat-policies.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +# Generate LavaMoat policies for the extension background script for each build +# type. +# ATTN: This may tax your device when running it locally. +concurrently --kill-others-on-fail -n main,beta,flask \ + "WRITE_AUTO_POLICY=1 yarn build scripts:prod --policy-only" \ + "WRITE_AUTO_POLICY=1 yarn build scripts:prod --policy-only --build-type beta" \ + "WRITE_AUTO_POLICY=1 yarn build scripts:prod --policy-only --build-type flask" diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index a37a7936e..04d889de5 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -216,7 +216,12 @@ async function verifyEnglishLocale() { } // never consider these messages as unused - const messageExceptions = ['appName', 'appDescription']; + const messageExceptions = [ + 'appName', + 'appNameBeta', + 'appNameFlask', + 'appDescription', + ]; const englishMessages = Object.keys(englishLocale); const unusedMessages = englishMessages.filter( diff --git a/lavamoat/browserify/policy-override.json b/lavamoat/browserify/beta/policy-override.json similarity index 100% rename from lavamoat/browserify/policy-override.json rename to lavamoat/browserify/beta/policy-override.json diff --git a/lavamoat/browserify/policy.json b/lavamoat/browserify/beta/policy.json similarity index 99% rename from lavamoat/browserify/policy.json rename to lavamoat/browserify/beta/policy.json index 7ac317102..3cfd712fa 100644 --- a/lavamoat/browserify/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -325,6 +325,7 @@ "@ethersproject/bignumber": true, "@ethersproject/bytes": true, "@ethersproject/keccak256": true, + "@ethersproject/logger": true, "@ethersproject/sha2": true, "@ethersproject/strings": true } @@ -1555,11 +1556,15 @@ }, "eth-json-rpc-middleware": { "globals": { + "URL": true, + "btoa": true, "console.error": true, "fetch": true, "setTimeout": true }, "packages": { + "@metamask/safe-event-emitter": true, + "browser-resolve": true, "btoa": true, "clone": true, "eth-rpc-errors": true, diff --git a/lavamoat/browserify/flask/policy-override.json b/lavamoat/browserify/flask/policy-override.json new file mode 100644 index 000000000..71fd98f61 --- /dev/null +++ b/lavamoat/browserify/flask/policy-override.json @@ -0,0 +1,55 @@ +{ + "resources": { + "browser-resolve": { + "packages": { + "core-js": true + } + }, + "babel-runtime": { + "packages": { + "@babel/runtime": true + } + }, + "node-fetch": { + "globals": { + "fetch": true + } + }, + "lodash": { + "globals": { + "setTimeout": true, + "clearTimeout": true + } + }, + "@ethersproject/random": { + "globals": { + "crypto.getRandomValues": true + } + }, + "browser-passworder": { + "globals": { + "crypto": true + } + }, + "randombytes": { + "globals": { + "crypto.getRandomValues": true + } + }, + "extensionizer": { + "globals": { + "console": true + } + }, + "web3": { + "globals": { + "XMLHttpRequest": true + } + }, + "storage": { + "globals": { + "localStorage": true + } + } + } +} diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json new file mode 100644 index 000000000..3cfd712fa --- /dev/null +++ b/lavamoat/browserify/flask/policy.json @@ -0,0 +1,4772 @@ +{ + "resources": { + "3box": { + "globals": { + "console.error": true, + "console.log": true, + "console.warn": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "3box-orbitdb-plugins": true, + "3id-resolver": true, + "@babel/runtime": true, + "buffer": true, + "did-jwt": true, + "elliptic": true, + "ethers": true, + "graphql-request": true, + "https-did-resolver": true, + "ipfs": true, + "ipfs-did-document": true, + "ipfs-log": true, + "ipfs-mini": true, + "is-ipfs": true, + "js-sha256": true, + "multihashes": true, + "muport-did-resolver": true, + "node-fetch": true, + "orbit-db": true, + "orbit-db-access-controllers": true, + "orbit-db-identity-provider": true, + "orbit-db-pubsub": true, + "process": true, + "store": true, + "tweetnacl": true, + "tweetnacl-util": true + } + }, + "3box-orbitdb-plugins": { + "globals": { + "console.log": true + }, + "packages": { + "base64url": true, + "did-jwt": true, + "did-resolver": true, + "events": true, + "ipfs-log": true, + "is-ipfs": true, + "orbit-db-access-controllers": true, + "orbit-db-io": true, + "safe-buffer": true + } + }, + "3id-resolver": { + "packages": { + "@babel/runtime": true, + "base64url": true, + "did-jwt": true, + "did-resolver": true, + "ipfs-did-document": true + } + }, + "@babel/runtime": { + "packages": { + "regenerator-runtime": true + } + }, + "@download/blockies": { + "globals": { + "document.createElement": true + } + }, + "@ensdomains/content-hash": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "cids": true, + "js-base64": true, + "multicodec": true, + "multihashes": true + } + }, + "@eth-optimism/contracts": { + "packages": { + "@ethersproject/abstract-provider": true, + "ethers": true + } + }, + "@ethereumjs/common": { + "packages": { + "buffer": true, + "crc-32": true, + "ethereumjs-util": true, + "events": true + } + }, + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/common": true, + "buffer": true, + "ethereumjs-util": true, + "is-buffer": true + } + }, + "@ethersproject/abi": { + "globals": { + "console.log": true + }, + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/hash": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/logger": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/address": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/rlp": true + } + }, + "@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/bytes": true + } + }, + "@ethersproject/basex": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/bignumber": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "bn.js": true + } + }, + "@ethersproject/bytes": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/constants": { + "packages": { + "@ethersproject/bignumber": true + } + }, + "@ethersproject/contracts": { + "globals": { + "setTimeout": true + }, + "packages": { + "@ethersproject/abi": true, + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/transactions": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/hdnode": { + "packages": { + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/pbkdf2": true, + "@ethersproject/properties": true, + "@ethersproject/sha2": true, + "@ethersproject/signing-key": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/wordlists": true + } + }, + "@ethersproject/json-wallets": { + "packages": { + "@ethersproject/address": true, + "@ethersproject/bytes": true, + "@ethersproject/hdnode": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/pbkdf2": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "aes-js": true, + "scrypt-js": true + } + }, + "@ethersproject/keccak256": { + "packages": { + "@ethersproject/bytes": true, + "js-sha3": true + } + }, + "@ethersproject/logger": { + "globals": { + "console": true + } + }, + "@ethersproject/networks": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/pbkdf2": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/sha2": true + } + }, + "@ethersproject/properties": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/providers": { + "globals": { + "WebSocket": true, + "clearInterval": true, + "clearTimeout": true, + "console.log": true, + "console.warn": true, + "name": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/hash": true, + "@ethersproject/logger": true, + "@ethersproject/networks": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/sha2": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/web": true, + "bech32": true + } + }, + "@ethersproject/random": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/rlp": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/sha2": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "hash.js": true + } + }, + "@ethersproject/signing-key": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "elliptic": true + } + }, + "@ethersproject/solidity": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/sha2": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/strings": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/transactions": { + "globals": { + "console.log": true + }, + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/rlp": true, + "@ethersproject/signing-key": true + } + }, + "@ethersproject/units": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/bytes": true, + "@ethersproject/hash": true, + "@ethersproject/hdnode": true, + "@ethersproject/json-wallets": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/signing-key": true, + "@ethersproject/transactions": true + } + }, + "@ethersproject/web": { + "globals": { + "clearTimeout": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/base64": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/wordlists": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/hash": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@formatjs/intl-relativetimeformat": { + "globals": { + "Intl": true + }, + "packages": { + "@formatjs/intl-utils": true + } + }, + "@formatjs/intl-utils": { + "globals": { + "Intl.getCanonicalLocales": true + } + }, + "@material-ui/core": { + "globals": { + "Image": true, + "_formatMuiErrorMessage": true, + "addEventListener": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "getSelection": true, + "innerHeight": true, + "innerWidth": true, + "matchMedia": true, + "navigator": true, + "performance.now": true, + "removeEventListener": true, + "requestAnimationFrame": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/styles": true, + "@material-ui/system": true, + "@material-ui/utils": true, + "clsx": true, + "hoist-non-react-statics": true, + "popper.js": true, + "prop-types": true, + "react": true, + "react-dom": true, + "react-is": true, + "react-transition-group": true + } + }, + "@material-ui/styles": { + "globals": { + "console.error": true, + "console.warn": true, + "document.createComment": true, + "document.head": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/utils": true, + "clsx": true, + "hoist-non-react-statics": true, + "jss": true, + "jss-plugin-camel-case": true, + "jss-plugin-default-unit": true, + "jss-plugin-global": true, + "jss-plugin-nested": true, + "jss-plugin-props-sort": true, + "jss-plugin-rule-value-function": true, + "jss-plugin-vendor-prefixer": true, + "prop-types": true, + "react": true + } + }, + "@material-ui/system": { + "globals": { + "console.error": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/utils": true, + "prop-types": true + } + }, + "@material-ui/utils": { + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react-is": true + } + }, + "@metamask/controllers": { + "globals": { + "Headers": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "@metamask/contract-metadata": true, + "abort-controller": true, + "async-mutex": true, + "await-semaphore": true, + "buffer": true, + "eth-ens-namehash": true, + "eth-json-rpc-infura": true, + "eth-keyring-controller": true, + "eth-method-registry": true, + "eth-phishing-detect": true, + "eth-query": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "ethereumjs-tx": true, + "ethereumjs-util": true, + "ethereumjs-wallet": true, + "ethers": true, + "ethjs-query": true, + "ethjs-unit": true, + "ethjs-util": true, + "events": true, + "human-standard-collectible-abi": true, + "human-standard-token-abi": true, + "immer": true, + "isomorphic-fetch": true, + "jsonschema": true, + "nanoid": true, + "punycode": true, + "single-call-balance-checker-abi": true, + "uuid": true, + "web3": true, + "web3-provider-engine": true + } + }, + "@metamask/eth-ledger-bridge-keyring": { + "globals": { + "addEventListener": true, + "console.log": true, + "document.createElement": true, + "document.head.appendChild": true, + "fetch": true, + "removeEventListener": true + }, + "packages": { + "@ethereumjs/tx": true, + "buffer": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "events": true, + "hdkey": true + } + }, + "@metamask/eth-token-tracker": { + "globals": { + "console.warn": true + }, + "packages": { + "@babel/runtime": true, + "deep-equal": true, + "eth-block-tracker": true, + "ethjs": true, + "ethjs-contract": true, + "ethjs-query": true, + "human-standard-token-abi": true, + "safe-event-emitter": true + } + }, + "@metamask/etherscan-link": { + "globals": { + "URL": true + } + }, + "@metamask/jazzicon": { + "globals": { + "document.createElement": true, + "document.createElementNS": true + }, + "packages": { + "color": true, + "mersenne-twister": true + } + }, + "@metamask/logo": { + "globals": { + "addEventListener": true, + "document.body.appendChild": true, + "document.createElementNS": true, + "innerHeight": true, + "innerWidth": true, + "requestAnimationFrame": true + }, + "packages": { + "gl-mat4": true, + "gl-vec3": true + } + }, + "@metamask/obs-store": { + "globals": { + "localStorage": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "stream-browserify": true, + "through2": true + } + }, + "@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "events": true + } + }, + "@popperjs/core": { + "globals": { + "Element": true, + "HTMLElement": true, + "ShadowRoot": true, + "console.error": true, + "console.warn": true, + "document": true, + "navigator.userAgent": true + } + }, + "@reduxjs/toolkit": { + "globals": { + "AbortController": true, + "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, + "__REDUX_DEVTOOLS_EXTENSION__": true, + "console.error": true, + "console.info": true, + "console.warn": true + }, + "packages": { + "immer": true, + "redux": true, + "redux-thunk": true, + "reselect": true + } + }, + "@segment/loosely-validate-event": { + "packages": { + "assert": true, + "buffer": true, + "component-type": true, + "join-component": true + } + }, + "@sentry/browser": { + "globals": { + "XMLHttpRequest": true, + "setTimeout": true + }, + "packages": { + "@sentry/core": true, + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/core": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@sentry/hub": true, + "@sentry/minimal": true, + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/hub": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/integrations": { + "globals": { + "clearTimeout": true, + "console.error": true, + "console.log": true, + "setTimeout": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "localforage": true, + "tslib": true + } + }, + "@sentry/minimal": { + "packages": { + "@sentry/hub": true, + "tslib": true + } + }, + "@sentry/utils": { + "globals": { + "CustomEvent": true, + "DOMError": true, + "DOMException": true, + "Element": true, + "ErrorEvent": true, + "Event": true, + "Headers": true, + "Request": true, + "Response": true, + "XMLHttpRequest.prototype": true, + "clearTimeout": true, + "console.error": true, + "document": true, + "setTimeout": true + }, + "packages": { + "process": true, + "tslib": true + } + }, + "@sindresorhus/is": { + "packages": { + "is-buffer": true, + "util": true + } + }, + "@zxing/library": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "btoa": true, + "clearTimeout": true, + "define": true, + "document.createElement": true, + "document.createElementNS": true, + "document.getElementById": true, + "navigator.mediaDevices.enumerateDevices": true, + "navigator.mediaDevices.getUserMedia": true, + "setTimeout": true + } + }, + "abort-controller": { + "globals": { + "AbortController": true + } + }, + "abstract-leveldown": { + "packages": { + "is-buffer": true, + "process": true, + "xtend": true + } + }, + "accounting": { + "globals": { + "define": true + } + }, + "aes-js": { + "globals": { + "define": true + } + }, + "analytics-node": { + "globals": { + "clearTimeout": true, + "console.log": true, + "setImmediate": true, + "setTimeout": true + }, + "packages": { + "@segment/loosely-validate-event": true, + "assert": true, + "axios": true, + "axios-retry": true, + "lodash.isstring": true, + "md5": true, + "ms": true, + "process": true, + "remove-trailing-slash": true, + "uuid": true + } + }, + "asap": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "document.createTextNode": true, + "setInterval": true, + "setTimeout": true + } + }, + "asn1.js": { + "packages": { + "bn.js": true, + "buffer": true, + "inherits": true, + "minimalistic-assert": true, + "vm-browserify": true + } + }, + "assemblyscript": { + "globals": { + "WebAssembly.Instance": true, + "WebAssembly.Module": true, + "WebAssembly.instantiateStreaming": true, + "console.log": true + } + }, + "assert": { + "globals": { + "Buffer": true + }, + "packages": { + "object-assign": true, + "util": true + } + }, + "async": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "lodash": true, + "process": true, + "timers-browserify": true + } + }, + "async-iterator-to-pull-stream": { + "packages": { + "get-iterator": true, + "pull-stream-to-async-iterator": true + } + }, + "async-iterator-to-stream": { + "packages": { + "process": true, + "readable-stream": true + } + }, + "async-mutex": { + "globals": { + "setTimeout": true + }, + "packages": { + "tslib": true + } + }, + "await-semaphore": { + "packages": { + "process": true, + "timers-browserify": true + } + }, + "axios": { + "globals": { + "FormData": true, + "URLSearchParams": true, + "XMLHttpRequest": true, + "btoa": true, + "console.warn": true, + "document": true, + "location.href": true, + "navigator": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "axios-retry": { + "globals": { + "setTimeout": true + }, + "packages": { + "is-retry-allowed": true + } + }, + "babel-runtime": { + "packages": { + "core-js": true, + "regenerator-runtime": true + } + }, + "backoff": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "events": true, + "precond": true, + "util": true + } + }, + "base-x": { + "packages": { + "safe-buffer": true + } + }, + "base32-encode": { + "packages": { + "to-data-view": true + } + }, + "base64url": { + "packages": { + "buffer": true + } + }, + "bignumber.js": { + "globals": { + "crypto": true, + "define": true + }, + "packages": { + "crypto-browserify": true + } + }, + "bip39": { + "packages": { + "create-hash": true, + "pbkdf2": true, + "randombytes": true, + "safe-buffer": true, + "unorm": true + } + }, + "bip66": { + "packages": { + "safe-buffer": true + } + }, + "bitwise": { + "packages": { + "buffer": true + } + }, + "bl": { + "packages": { + "buffer": true, + "readable-stream": true, + "util": true + } + }, + "blakejs": { + "globals": { + "console.log": true + }, + "packages": { + "buffer": true + } + }, + "blob": { + "globals": { + "Blob": true, + "MSBlobBuilder": true, + "MozBlobBuilder": true, + "WebKitBlobBuilder": true + } + }, + "bn.js": { + "packages": { + "browser-resolve": true + } + }, + "borc": { + "globals": { + "console": true + }, + "packages": { + "bignumber.js": true, + "buffer": true, + "ieee754": true, + "iso-url": true + } + }, + "brorand": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "browser-resolve": true + } + }, + "browser-passworder": { + "globals": { + "btoa": true, + "crypto.getRandomValues": true, + "crypto.subtle.decrypt": true, + "crypto.subtle.deriveKey": true, + "crypto.subtle.encrypt": true, + "crypto.subtle.importKey": true + }, + "packages": { + "browserify-unibabel": true + } + }, + "browserify-aes": { + "packages": { + "buffer": true, + "buffer-xor": true, + "cipher-base": true, + "evp_bytestokey": true, + "inherits": true, + "safe-buffer": true + } + }, + "browserify-cipher": { + "packages": { + "browserify-aes": true, + "browserify-des": true, + "evp_bytestokey": true + } + }, + "browserify-des": { + "packages": { + "buffer": true, + "cipher-base": true, + "des.js": true, + "inherits": true + } + }, + "browserify-rsa": { + "packages": { + "bn.js": true, + "buffer": true, + "randombytes": true + } + }, + "browserify-sign": { + "packages": { + "bn.js": true, + "browserify-rsa": true, + "buffer": true, + "create-hash": true, + "create-hmac": true, + "elliptic": true, + "inherits": true, + "parse-asn1": true, + "stream-browserify": true + } + }, + "browserify-unibabel": { + "globals": { + "atob": true, + "btoa": true + } + }, + "bs58": { + "packages": { + "base-x": true + } + }, + "bs58check": { + "packages": { + "bs58": true, + "create-hash": true, + "safe-buffer": true + } + }, + "btoa": { + "packages": { + "buffer": true + } + }, + "buffer": { + "globals": { + "console": true + }, + "packages": { + "base64-js": true, + "ieee754": true + } + }, + "buffer-split": { + "packages": { + "buffer-indexof": true + } + }, + "buffer-xor": { + "packages": { + "buffer": true + } + }, + "cids": { + "packages": { + "buffer": true, + "class-is": true, + "is-buffer": true, + "multibase": true, + "multicodec": true, + "multihashes": true, + "uint8arrays": true + } + }, + "cipher-base": { + "packages": { + "inherits": true, + "safe-buffer": true, + "stream-browserify": true, + "string_decoder": true + } + }, + "classnames": { + "globals": { + "classNames": "write", + "define": true + } + }, + "clone": { + "packages": { + "buffer": true + } + }, + "coinstring": { + "packages": { + "bs58": true, + "buffer": true, + "create-hash": true + } + }, + "color": { + "packages": { + "clone": true, + "color-convert": true, + "color-string": true + } + }, + "color-convert": { + "packages": { + "color-name": true + } + }, + "color-string": { + "packages": { + "color-name": true + } + }, + "cookiejar": { + "globals": { + "console.warn": true + } + }, + "copy-to-clipboard": { + "globals": { + "clipboardData.setData": true, + "console.error": true, + "console.warn": true, + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true, + "document.createRange": true, + "document.execCommand": true, + "document.getSelection": true, + "navigator.userAgent": true, + "prompt": true + }, + "packages": { + "toggle-selection": true + } + }, + "core-js": { + "globals": { + "PromiseRejectionEvent": true, + "__e": "write", + "__g": "write", + "document.createTextNode": true, + "postMessage": true, + "setTimeout": true + } + }, + "core-util-is": { + "packages": { + "is-buffer": true + } + }, + "crc-32": { + "globals": { + "DO_NOT_EXPORT_CRC": true, + "define": true + } + }, + "create-ecdh": { + "packages": { + "bn.js": true, + "buffer": true, + "elliptic": true + } + }, + "create-hash": { + "packages": { + "cipher-base": true, + "inherits": true, + "md5.js": true, + "ripemd160": true, + "sha.js": true + } + }, + "create-hmac": { + "packages": { + "cipher-base": true, + "create-hash": true, + "inherits": true, + "ripemd160": true, + "safe-buffer": true, + "sha.js": true + } + }, + "cross-fetch": { + "globals": { + "Blob": true, + "FileReader": true, + "FormData": true, + "URLSearchParams.prototype.isPrototypeOf": true, + "XMLHttpRequest": true + } + }, + "crypto-browserify": { + "packages": { + "browserify-cipher": true, + "browserify-sign": true, + "create-ecdh": true, + "create-hash": true, + "create-hmac": true, + "diffie-hellman": true, + "pbkdf2": true, + "public-encrypt": true, + "randombytes": true, + "randomfill": true + } + }, + "crypto-js": { + "globals": { + "define": true + } + }, + "css-vendor": { + "globals": { + "document.createElement": true, + "document.documentElement": true, + "getComputedStyle": true + }, + "packages": { + "@babel/runtime": true, + "is-in-browser": true + } + }, + "currency-formatter": { + "packages": { + "accounting": true, + "locale-currency": true, + "object-assign": true + } + }, + "data-queue": { + "packages": { + "events": true + } + }, + "datastore-core": { + "packages": { + "async": true, + "buffer": true, + "interface-datastore": true, + "pull-many": true, + "pull-stream": true + } + }, + "datastore-level": { + "packages": { + "buffer": true, + "encoding-down": true, + "interface-datastore": true, + "level-js": true, + "levelup": true, + "pull-stream": true + } + }, + "datastore-pubsub": { + "packages": { + "assert": true, + "buffer": true, + "debug": true, + "err-code": true, + "interface-datastore": true, + "multibase": true + } + }, + "debounce": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "debounce-stream": { + "packages": { + "debounce": true, + "duplexer": true, + "through": true + } + }, + "debug": { + "globals": { + "chrome": true, + "console": true, + "document": true, + "localStorage": true, + "navigator": true, + "process": true + }, + "packages": { + "ms": true, + "process": true + } + }, + "deep-equal": { + "packages": { + "is-arguments": true, + "is-date-object": true, + "is-regex": true, + "object-is": true, + "object-keys": true, + "regexp.prototype.flags": true + } + }, + "deep-extend": { + "packages": { + "buffer": true + } + }, + "deferred-leveldown": { + "packages": { + "abstract-leveldown": true, + "inherits": true + } + }, + "define-properties": { + "packages": { + "object-keys": true + } + }, + "des.js": { + "packages": { + "inherits": true, + "minimalistic-assert": true + } + }, + "did-jwt": { + "packages": { + "@babel/runtime": true, + "@stablelib/utf8": true, + "base64url": true, + "buffer": true, + "did-resolver": true, + "elliptic": true, + "js-sha256": true, + "js-sha3": true, + "tweetnacl": true, + "tweetnacl-util": true, + "uport-base64url": true + } + }, + "diffie-hellman": { + "packages": { + "bn.js": true, + "buffer": true, + "miller-rabin": true, + "randombytes": true + } + }, + "dlv": { + "globals": { + "define": true + } + }, + "dnd-core": { + "packages": { + "asap": true, + "invariant": true, + "lodash": true, + "redux": true + } + }, + "dom-helpers": { + "globals": { + "document": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true + } + }, + "drbg.js": { + "packages": { + "buffer": true, + "create-hmac": true + } + }, + "duplexer": { + "packages": { + "stream-browserify": true + } + }, + "elliptic": { + "packages": { + "bn.js": true, + "brorand": true, + "hash.js": true, + "hmac-drbg": true, + "inherits": true, + "minimalistic-assert": true, + "minimalistic-crypto-utils": true + } + }, + "encoding-down": { + "packages": { + "abstract-leveldown": true, + "inherits": true, + "level-codec": true, + "level-errors": true + } + }, + "end-of-stream": { + "packages": { + "once": true, + "process": true + } + }, + "engine.io-client": { + "globals": { + "MozWebSocket": true, + "WebSocket": true, + "XDomainRequest": true, + "XMLHttpRequest": true, + "addEventListener": true, + "attachEvent": true, + "clearTimeout": true, + "document": true, + "location": true, + "navigator": true, + "setTimeout": true + }, + "packages": { + "browser-resolve": true, + "buffer": true, + "component-emitter": true, + "component-inherit": true, + "debug": true, + "engine.io-parser": true, + "has-cors": true, + "indexof": true, + "parseqs": true, + "parseuri": true, + "yeast": true + } + }, + "engine.io-parser": { + "globals": { + "FileReader": true, + "btoa": true, + "navigator": true + }, + "packages": { + "after": true, + "arraybuffer.slice": true, + "base64-arraybuffer": true, + "blob": true, + "has-binary2": true + } + }, + "errno": { + "packages": { + "prr": true + } + }, + "es-abstract": { + "packages": { + "function-bind": true, + "has-symbols": true + } + }, + "eth-block-tracker": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "eth-query": true, + "json-rpc-random-id": true, + "pify": true, + "safe-event-emitter": true + } + }, + "eth-ens-namehash": { + "globals": { + "name": "write" + }, + "packages": { + "buffer": true, + "idna-uts46": true, + "idna-uts46-hx": true, + "js-sha3": true + } + }, + "eth-hd-keyring": { + "packages": { + "bip39": true, + "eth-sig-util": true, + "eth-simple-keyring": true, + "ethereumjs-wallet": true + } + }, + "eth-json-rpc-filters": { + "globals": { + "console.error": true, + "results": "write" + }, + "packages": { + "await-semaphore": true, + "eth-json-rpc-middleware": true, + "eth-query": true, + "json-rpc-engine": true, + "lodash.flatmap": true, + "pify": true, + "safe-event-emitter": true + } + }, + "eth-json-rpc-infura": { + "globals": { + "setTimeout": true + }, + "packages": { + "eth-json-rpc-middleware": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "node-fetch": true + } + }, + "eth-json-rpc-middleware": { + "globals": { + "URL": true, + "btoa": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "browser-resolve": true, + "btoa": true, + "clone": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "json-rpc-engine": true, + "json-stable-stringify": true, + "node-fetch": true, + "pify": true, + "safe-event-emitter": true, + "url": true + } + }, + "eth-keyring-controller": { + "packages": { + "bip39": true, + "browser-passworder": true, + "eth-hd-keyring": true, + "eth-sig-util": true, + "eth-simple-keyring": true, + "ethereumjs-util": true, + "events": true, + "loglevel": true, + "obs-store": true + } + }, + "eth-lattice-keyring": { + "globals": { + "addEventListener": true, + "browser": true, + "clearInterval": true, + "console.warn": true, + "open": true, + "setInterval": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "bignumber.js": true, + "buffer": true, + "crypto-browserify": true, + "ethereumjs-util": true, + "events": true, + "gridplus-sdk": true + } + }, + "eth-method-registry": { + "packages": { + "ethjs": true + } + }, + "eth-phishing-detect": { + "packages": { + "fast-levenshtein": true + } + }, + "eth-query": { + "packages": { + "json-rpc-random-id": true, + "xtend": true + } + }, + "eth-rpc-errors": { + "packages": { + "fast-safe-stringify": true + } + }, + "eth-sig-util": { + "packages": { + "buffer": true, + "ethereumjs-abi": true, + "ethereumjs-util": true, + "tweetnacl": true, + "tweetnacl-util": true + } + }, + "eth-simple-keyring": { + "packages": { + "buffer": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "ethereumjs-wallet": true, + "events": true + } + }, + "eth-trezor-keyring": { + "globals": { + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx": true, + "buffer": true, + "ethereumjs-util": true, + "events": true, + "hdkey": true, + "trezor-connect": true + } + }, + "ethereum-cryptography": { + "packages": { + "assert": true, + "bs58check": true, + "buffer": true, + "create-hmac": true, + "hash.js": true, + "keccak": true, + "randombytes": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "ethereumjs-abi": { + "packages": { + "bn.js": true, + "buffer": true, + "ethereumjs-util": true + } + }, + "ethereumjs-tx": { + "packages": { + "buffer": true, + "ethereum-common": true, + "ethereumjs-util": true + } + }, + "ethereumjs-util": { + "packages": { + "assert": true, + "bn.js": true, + "buffer": true, + "create-hash": true, + "elliptic": true, + "ethereum-cryptography": true, + "ethjs-util": true, + "is-buffer": true, + "keccak": true, + "rlp": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "ethereumjs-wallet": { + "packages": { + "aes-js": true, + "bs58check": true, + "buffer": true, + "crypto-browserify": true, + "ethereum-cryptography": true, + "ethereumjs-util": true, + "randombytes": true, + "safe-buffer": true, + "scrypt-js": true, + "scryptsy": true, + "utf8": true, + "uuid": true + } + }, + "ethers": { + "globals": { + "MessageChannel": true, + "XMLHttpRequest": true, + "atob": true, + "btoa": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "crypto.getRandomValues": true, + "define": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/abi": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/base64": true, + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/contracts": true, + "@ethersproject/hash": true, + "@ethersproject/hdnode": true, + "@ethersproject/json-wallets": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/providers": true, + "@ethersproject/random": true, + "@ethersproject/rlp": true, + "@ethersproject/sha2": true, + "@ethersproject/signing-key": true, + "@ethersproject/solidity": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/units": true, + "@ethersproject/wallet": true, + "@ethersproject/web": true, + "@ethersproject/wordlists": true + } + }, + "ethers-eip712": { + "packages": { + "ethers": true + } + }, + "ethjs": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "bn.js": true, + "buffer": true, + "ethjs-abi": true, + "ethjs-contract": true, + "ethjs-filter": true, + "ethjs-provider-http": true, + "ethjs-query": true, + "ethjs-unit": true, + "ethjs-util": true, + "js-sha3": true, + "number-to-bn": true + } + }, + "ethjs-abi": { + "packages": { + "bn.js": true, + "buffer": true, + "js-sha3": true, + "number-to-bn": true + } + }, + "ethjs-contract": { + "packages": { + "babel-runtime": true, + "ethjs-abi": true, + "ethjs-filter": true, + "ethjs-util": true, + "js-sha3": true, + "promise-to-callback": true + } + }, + "ethjs-ens": { + "packages": { + "eth-ens-namehash": true, + "ethereum-ens-network-map": true, + "ethjs-contract": true, + "ethjs-query": true + } + }, + "ethjs-filter": { + "globals": { + "clearInterval": true, + "setInterval": true + } + }, + "ethjs-format": { + "packages": { + "ethjs-schema": true, + "ethjs-util": true, + "number-to-bn": true, + "strip-hex-prefix": true + } + }, + "ethjs-provider-http": { + "packages": { + "xhr2": true + } + }, + "ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "babel-runtime": true, + "ethjs-format": true, + "ethjs-rpc": true, + "promise-to-callback": true + } + }, + "ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, + "ethjs-unit": { + "packages": { + "bn.js": true, + "number-to-bn": true + } + }, + "ethjs-util": { + "packages": { + "buffer": true, + "is-hex-prefixed": true, + "strip-hex-prefix": true + } + }, + "events": { + "globals": { + "console": true + } + }, + "evp_bytestokey": { + "packages": { + "md5.js": true, + "safe-buffer": true + } + }, + "extension-port-stream": { + "packages": { + "buffer": true, + "stream-browserify": true + } + }, + "extensionizer": { + "globals": { + "browser": true, + "chrome": true + } + }, + "fast-json-patch": { + "globals": { + "addEventListener": true, + "clearTimeout": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "fast-deep-equal": true + } + }, + "fast-levenshtein": { + "globals": { + "Intl": true, + "Levenshtein": "write", + "console.log": true, + "define": true, + "importScripts": true, + "postMessage": true + } + }, + "fsm-event": { + "packages": { + "assert": true, + "events": true, + "fsm": true + } + }, + "fuse.js": { + "globals": { + "console": true, + "define": true + } + }, + "get-browser-rtc": { + "globals": { + "RTCIceCandidate": true, + "RTCPeerConnection": true, + "RTCSessionDescription": true, + "mozRTCIceCandidate": true, + "mozRTCPeerConnection": true, + "mozRTCSessionDescription": true, + "webkitRTCIceCandidate": true, + "webkitRTCPeerConnection": true, + "webkitRTCSessionDescription": true + } + }, + "get-params": { + "globals": { + "GetParams": "write" + } + }, + "graphql-request": { + "globals": { + "fetch": true + }, + "packages": { + "cross-fetch": true + } + }, + "gridplus-sdk": { + "globals": { + "console.error": true, + "setTimeout": true + }, + "packages": { + "aes-js": true, + "bech32": true, + "bignumber.js": true, + "bitwise": true, + "borc": true, + "bs58check": true, + "buffer": true, + "crc-32": true, + "elliptic": true, + "ethers": true, + "ethers-eip712": true, + "js-sha3": true, + "rlp-browser": true, + "secp256k1": true, + "superagent": true + } + }, + "hamt-sharding": { + "packages": { + "is-buffer": true, + "sparse-array": true + } + }, + "has-binary2": { + "globals": { + "Blob": true, + "File": true + }, + "packages": { + "buffer": true, + "isarray": true + } + }, + "has-cors": { + "globals": { + "XMLHttpRequest": true + } + }, + "hash-base": { + "packages": { + "inherits": true, + "safe-buffer": true, + "stream-browserify": true + } + }, + "hash.js": { + "packages": { + "inherits": true, + "minimalistic-assert": true + } + }, + "hdkey": { + "packages": { + "assert": true, + "coinstring": true, + "crypto-browserify": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "heap": { + "globals": { + "define": true + } + }, + "hi-base32": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "history": { + "globals": { + "addEventListener": true, + "confirm": true, + "document": true, + "history": true, + "location": true, + "navigator.userAgent": true, + "removeEventListener": true + }, + "packages": { + "resolve-pathname": true, + "tiny-invariant": true, + "tiny-warning": true, + "value-equal": true + } + }, + "hmac-drbg": { + "packages": { + "hash.js": true, + "minimalistic-assert": true, + "minimalistic-crypto-utils": true + } + }, + "hoist-non-react-statics": { + "packages": { + "react-is": true + } + }, + "https-browserify": { + "packages": { + "stream-http": true, + "url": true + } + }, + "https-did-resolver": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "browser-resolve": true, + "did-resolver": true + } + }, + "human-to-milliseconds": { + "packages": { + "promisify-es6": true + } + }, + "idb-readable-stream": { + "globals": { + "IDBKeyRange.bound": true, + "IDBKeyRange.lowerBound": true, + "IDBKeyRange.upperBound": true + }, + "packages": { + "stream-browserify": true, + "xtend": true + } + }, + "idna-uts46": { + "globals": { + "define": true + }, + "packages": { + "punycode": true + } + }, + "idna-uts46-hx": { + "globals": { + "define": true + }, + "packages": { + "punycode": true + } + }, + "immediate": { + "globals": { + "MessageChannel": true, + "MutationObserver": true, + "WebKitMutationObserver": true, + "clearTimeout": true, + "document.createElement": true, + "document.createTextNode": true, + "document.documentElement.appendChild": true, + "setImmediate": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "interface-connection": { + "packages": { + "pull-defer": true + } + }, + "interface-datastore": { + "packages": { + "async": true, + "buffer": true, + "class-is": true, + "err-code": true, + "os-browserify": true, + "path-browserify": true, + "pull-defer": true, + "pull-stream": true, + "uuid": true + } + }, + "ip": { + "packages": { + "buffer": true, + "os-browserify": true + } + }, + "ipfs": { + "globals": { + "AbortController": true, + "clearInterval": true, + "clearTimeout": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "async": true, + "async-iterator-all": true, + "async-iterator-to-pull-stream": true, + "async-iterator-to-stream": true, + "base32.js": true, + "bignumber.js": true, + "browser-resolve": true, + "buffer": true, + "callbackify": true, + "cids": true, + "class-is": true, + "datastore-core": true, + "datastore-pubsub": true, + "debug": true, + "dlv": true, + "err-code": true, + "events": true, + "fnv1a": true, + "fsm-event": true, + "human-to-milliseconds": true, + "interface-datastore": true, + "ipfs-bitswap": true, + "ipfs-block": true, + "ipfs-block-service": true, + "ipfs-mfs": true, + "ipfs-repo": true, + "ipfs-unixfs": true, + "ipfs-unixfs-exporter": true, + "ipfs-unixfs-importer": true, + "ipfs-utils": true, + "ipld": true, + "ipld-dag-cbor": true, + "ipld-dag-pb": true, + "ipld-raw": true, + "ipns": true, + "is-buffer": true, + "is-ipfs": true, + "is-pull-stream": true, + "is-stream": true, + "iso-url": true, + "just-flatten-it": true, + "kind-of": true, + "libp2p": true, + "libp2p-bootstrap": true, + "libp2p-crypto": true, + "libp2p-kad-dht": true, + "libp2p-keychain": true, + "libp2p-record": true, + "libp2p-secio": true, + "libp2p-webrtc-star": true, + "libp2p-websocket-star-multi": true, + "libp2p-websockets": true, + "mafmt": true, + "merge-options": true, + "multiaddr": true, + "multiaddr-to-uri": true, + "multibase": true, + "multicodec": true, + "multihashes": true, + "multihashing-async": true, + "peer-book": true, + "peer-id": true, + "peer-info": true, + "promisify-es6": true, + "protons": true, + "pull-cat": true, + "pull-defer": true, + "pull-mplex": true, + "pull-pushable": true, + "pull-sort": true, + "pull-stream": true, + "pull-stream-to-async-iterator": true, + "pull-stream-to-stream": true, + "pull-traverse": true, + "readable-stream": true, + "receptacle": true, + "stream-to-pull-stream": true, + "superstruct": true, + "timers-browserify": true, + "varint": true + } + }, + "ipfs-bitswap": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "assert": true, + "async": true, + "bignumber.js": true, + "cids": true, + "debug": true, + "events": true, + "ipfs-block": true, + "just-debounce-it": true, + "lodash.isequalwith": true, + "moving-average": true, + "multicodec": true, + "multihashing-async": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true, + "varint-decoder": true + } + }, + "ipfs-block": { + "packages": { + "cids": true, + "class-is": true, + "is-buffer": true + } + }, + "ipfs-block-service": { + "packages": { + "async": true + } + }, + "ipfs-log": { + "globals": { + "clearTimeout": true, + "console.warn": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "json-stringify-deterministic": true, + "orbit-db-io": true, + "p-each-series": true, + "p-map": true, + "p-whilst": true + } + }, + "ipfs-mfs": { + "globals": { + "Blob": true, + "FileReader": true + }, + "packages": { + "assert": true, + "async-iterator-last": true, + "browser-resolve": true, + "buffer": true, + "cids": true, + "debug": true, + "err-code": true, + "hamt-sharding": true, + "interface-datastore": true, + "ipfs-unixfs": true, + "ipfs-unixfs-exporter": true, + "ipfs-unixfs-importer": true, + "ipld-dag-pb": true, + "mortice": true, + "multicodec": true, + "multihashes": true, + "promisify-es6": true + } + }, + "ipfs-mini": { + "globals": { + "XMLHttpRequest": true + } + }, + "ipfs-pubsub-1on1": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "events": true, + "path-browserify": true, + "safe-buffer": true + } + }, + "ipfs-pubsub-peer-monitor": { + "globals": { + "clearInterval": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "events": true + } + }, + "ipfs-repo": { + "packages": { + "assert": true, + "async": true, + "base32.js": true, + "bignumber.js": true, + "buffer": true, + "cids": true, + "datastore-core": true, + "datastore-level": true, + "debug": true, + "dlv": true, + "interface-datastore": true, + "ipfs-block": true, + "just-safe-set": true, + "path-browserify": true, + "pull-stream": true, + "sort-keys": true, + "timers-browserify": true + } + }, + "ipfs-unixfs": { + "packages": { + "protons": true + } + }, + "ipfs-unixfs-exporter": { + "packages": { + "async-iterator-last": true, + "buffer": true, + "cids": true, + "err-code": true, + "hamt-sharding": true, + "ipfs-unixfs": true, + "ipfs-unixfs-importer": true, + "is-buffer": true + } + }, + "ipfs-unixfs-importer": { + "packages": { + "async-iterator-all": true, + "async-iterator-batch": true, + "async-iterator-first": true, + "bl": true, + "buffer": true, + "deep-extend": true, + "err-code": true, + "hamt-sharding": true, + "ipfs-unixfs": true, + "ipld-dag-pb": true, + "multicodec": true, + "multihashes": true, + "multihashing-async": true, + "rabin-wasm": true, + "superstruct": true + } + }, + "ipfs-utils": { + "globals": { + "FileReader": true + }, + "packages": { + "is-buffer": true, + "is-pull-stream": true, + "is-stream": true, + "kind-of": true, + "readable-stream": true + } + }, + "ipld": { + "packages": { + "cids": true, + "ipfs-block": true, + "ipld-dag-cbor": true, + "ipld-dag-pb": true, + "ipld-raw": true, + "is-buffer": true, + "merge-options": true, + "multicodec": true, + "promisify-es6": true, + "typical": true + } + }, + "ipld-dag-cbor": { + "packages": { + "borc": true, + "buffer": true, + "cids": true, + "is-buffer": true, + "is-circular": true, + "multicodec": true, + "multihashing-async": true + } + }, + "ipld-dag-pb": { + "packages": { + "assert": true, + "buffer": true, + "cids": true, + "class-is": true, + "is-buffer": true, + "multicodec": true, + "multihashing-async": true, + "protons": true, + "stable": true + } + }, + "ipld-raw": { + "packages": { + "cids": true, + "multicodec": true, + "multihashing-async": true + } + }, + "ipns": { + "packages": { + "base32-encode": true, + "buffer": true, + "debug": true, + "interface-datastore": true, + "libp2p-crypto": true, + "multihashes": true, + "peer-id": true, + "protons": true, + "timestamp-nano": true + } + }, + "is-dom": { + "globals": { + "Node": true + }, + "packages": { + "is-object": true, + "is-window": true + } + }, + "is-in-browser": { + "globals": { + "document": true + } + }, + "is-ip": { + "packages": { + "ip-regex": true + } + }, + "is-ipfs": { + "packages": { + "bs58": true, + "buffer": true, + "cids": true, + "mafmt": true, + "multiaddr": true, + "multibase": true, + "multihashes": true + } + }, + "is-regex": { + "packages": { + "has-symbols": true + } + }, + "iso-random-stream": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "buffer": true + } + }, + "iso-url": { + "globals": { + "URL": true, + "URLSearchParams": true, + "location": true + } + }, + "isomorphic-fetch": { + "globals": { + "fetch.bind": true + }, + "packages": { + "whatwg-fetch": true + } + }, + "js-base64": { + "globals": { + "Base64": "write", + "TextDecoder": true, + "TextEncoder": true, + "atob": true, + "btoa": true, + "define": true + }, + "packages": { + "buffer": true + } + }, + "js-sha256": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "js-sha3": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "jsan": { + "globals": { + "console.warn": true + } + }, + "json-rpc-engine": { + "packages": { + "@metamask/safe-event-emitter": true, + "eth-rpc-errors": true, + "safe-event-emitter": true + } + }, + "json-rpc-middleware-stream": { + "packages": { + "readable-stream": true + } + }, + "json-stable-stringify": { + "packages": { + "jsonify": true + } + }, + "jsonschema": { + "packages": { + "url": true + } + }, + "jss": { + "globals": { + "CSS": true, + "document.createElement": true, + "document.querySelector": true + }, + "packages": { + "@babel/runtime": true, + "is-in-browser": true, + "tiny-warning": true + } + }, + "jss-plugin-camel-case": { + "packages": { + "hyphenate-style-name": true + } + }, + "jss-plugin-default-unit": { + "globals": { + "CSS": true + }, + "packages": { + "jss": true + } + }, + "jss-plugin-global": { + "packages": { + "@babel/runtime": true, + "jss": true + } + }, + "jss-plugin-nested": { + "packages": { + "@babel/runtime": true, + "tiny-warning": true + } + }, + "jss-plugin-rule-value-function": { + "packages": { + "jss": true, + "tiny-warning": true + } + }, + "jss-plugin-vendor-prefixer": { + "packages": { + "css-vendor": true, + "jss": true + } + }, + "just-debounce-it": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "k-bucket": { + "packages": { + "events": true, + "randombytes": true + } + }, + "keccak": { + "packages": { + "buffer": true, + "inherits": true, + "safe-buffer": true, + "stream-browserify": true + } + }, + "latency-monitor": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "document": true, + "performance": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "debug": true, + "events": true, + "lodash": true, + "process": true + } + }, + "level-codec": { + "packages": { + "buffer": true + } + }, + "level-errors": { + "packages": { + "errno": true + } + }, + "level-iterator-stream": { + "packages": { + "inherits": true, + "readable-stream": true, + "xtend": true + } + }, + "level-js": { + "globals": { + "IDBKeyRange.bound": true, + "IDBKeyRange.lowerBound": true, + "IDBKeyRange.only": true, + "IDBKeyRange.upperBound": true, + "indexedDB": true + }, + "packages": { + "abstract-leveldown": true, + "buffer": true, + "idb-readable-stream": true, + "immediate": true, + "inherits": true, + "is-buffer": true, + "ltgt": true, + "process": true, + "stream-browserify": true, + "typedarray-to-buffer": true, + "util": true, + "xtend": true + } + }, + "levelup": { + "packages": { + "assert": true, + "deferred-leveldown": true, + "events": true, + "level-errors": true, + "level-iterator-stream": true, + "process": true, + "util": true, + "xtend": true + } + }, + "libp2p": { + "packages": { + "async": true, + "debug": true, + "err-code": true, + "events": true, + "fsm-event": true, + "is-buffer": true, + "libp2p-connection-manager": true, + "libp2p-floodsub": true, + "libp2p-ping": true, + "libp2p-switch": true, + "libp2p-websockets": true, + "multiaddr": true, + "once": true, + "peer-book": true, + "peer-id": true, + "peer-info": true, + "process": true, + "superstruct": true + } + }, + "libp2p-bootstrap": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "async": true, + "debug": true, + "events": true, + "mafmt": true, + "multiaddr": true, + "peer-id": true, + "peer-info": true + } + }, + "libp2p-circuit": { + "packages": { + "async": true, + "debug": true, + "events": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-connection-manager": { + "packages": { + "debug": true, + "events": true, + "latency-monitor": true + } + }, + "libp2p-crypto": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "asn1.js": true, + "async": true, + "browserify-aes": true, + "bs58": true, + "buffer": true, + "iso-random-stream": true, + "libp2p-crypto-secp256k1": true, + "multihashing-async": true, + "node-forge": true, + "protons": true, + "tweetnacl": true + } + }, + "libp2p-crypto-secp256k1": { + "packages": { + "async": true, + "bs58": true, + "multihashing-async": true, + "secp256k1": true + } + }, + "libp2p-floodsub": { + "packages": { + "assert": true, + "async": true, + "debug": true, + "libp2p-pubsub": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-identify": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "multiaddr": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-kad-dht": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "abort-controller": true, + "assert": true, + "async": true, + "base32.js": true, + "buffer": true, + "cids": true, + "debug": true, + "err-code": true, + "events": true, + "hashlru": true, + "heap": true, + "interface-datastore": true, + "is-buffer": true, + "k-bucket": true, + "libp2p-crypto": true, + "libp2p-record": true, + "multihashes": true, + "multihashing-async": true, + "p-queue": true, + "p-times": true, + "peer-id": true, + "peer-info": true, + "promise-to-callback": true, + "promisify-es6": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true, + "pull-stream-to-async-iterator": true, + "varint": true, + "xor-distance": true + } + }, + "libp2p-keychain": { + "globals": { + "setTimeout": true + }, + "packages": { + "async": true, + "buffer": true, + "err-code": true, + "interface-datastore": true, + "libp2p-crypto": true, + "merge-options": true, + "node-forge": true, + "pull-stream": true, + "sanitize-filename": true + } + }, + "libp2p-ping": { + "packages": { + "debug": true, + "events": true, + "libp2p-crypto": true, + "pull-handshake": true, + "pull-stream": true + } + }, + "libp2p-pubsub": { + "packages": { + "async": true, + "bs58": true, + "buffer": true, + "debug": true, + "err-code": true, + "events": true, + "is-buffer": true, + "libp2p-crypto": true, + "protons": true, + "pull-length-prefixed": true, + "pull-pushable": true, + "pull-stream": true, + "time-cache": true + } + }, + "libp2p-record": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "buffer-split": true, + "err-code": true, + "is-buffer": true, + "multihashing-async": true, + "protons": true + } + }, + "libp2p-secio": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "debug": true, + "interface-connection": true, + "libp2p-crypto": true, + "multihashing-async": true, + "once": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-defer": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-switch": { + "packages": { + "assert": true, + "async": true, + "bignumber.js": true, + "class-is": true, + "debug": true, + "err-code": true, + "events": true, + "fsm-event": true, + "hashlru": true, + "interface-connection": true, + "libp2p-circuit": true, + "libp2p-identify": true, + "moving-average": true, + "multiaddr": true, + "multistream-select": true, + "once": true, + "peer-id": true, + "peer-info": true, + "pull-stream": true, + "retimer": true + } + }, + "libp2p-webrtc-star": { + "packages": { + "async": true, + "class-is": true, + "debug": true, + "events": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "simple-peer": true, + "socket.io-client": true, + "stream-to-pull-stream": true, + "webrtcsupport": true + } + }, + "libp2p-websocket-star": { + "globals": { + "console.error": true + }, + "packages": { + "async": true, + "buffer": true, + "class-is": true, + "debug": true, + "events": true, + "interface-connection": true, + "libp2p-crypto": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "pull-stream": true, + "socket.io-client": true, + "socket.io-pull-stream": true, + "uuid": true + } + }, + "libp2p-websocket-star-multi": { + "globals": { + "setTimeout": true + }, + "packages": { + "async": true, + "debug": true, + "events": true, + "libp2p-websocket-star": true, + "mafmt": true, + "multiaddr": true, + "once": true + } + }, + "libp2p-websockets": { + "packages": { + "class-is": true, + "debug": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "multiaddr-to-uri": true, + "os-browserify": true, + "pull-ws": true + } + }, + "locale-currency": { + "globals": { + "countryCode": true + } + }, + "localforage": { + "globals": { + "Blob": true, + "BlobBuilder": true, + "FileReader": true, + "IDBKeyRange": true, + "MSBlobBuilder": true, + "MozBlobBuilder": true, + "OIndexedDB": true, + "WebKitBlobBuilder": true, + "atob": true, + "btoa": true, + "console.error": true, + "console.info": true, + "console.warn": true, + "define": true, + "fetch": true, + "indexedDB": true, + "localStorage": true, + "mozIndexedDB": true, + "msIndexedDB": true, + "navigator.platform": true, + "navigator.userAgent": true, + "openDatabase": true, + "setTimeout": true, + "webkitIndexedDB": true + } + }, + "lodash": { + "globals": { + "define": true + } + }, + "lodash.throttle": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "loglevel": { + "globals": { + "console": true, + "define": true, + "document.cookie": true, + "localStorage": true, + "log": "write" + } + }, + "logplease": { + "globals": { + "LOG": true, + "console.error": true, + "console.log": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "process": true, + "util": true + } + }, + "lru": { + "packages": { + "events": true, + "inherits": true + } + }, + "ltgt": { + "packages": { + "is-buffer": true + } + }, + "luxon": { + "globals": { + "Intl": true + } + }, + "mafmt": { + "packages": { + "multiaddr": true + } + }, + "md5": { + "packages": { + "charenc": true, + "crypt": true, + "is-buffer": true + } + }, + "md5.js": { + "packages": { + "hash-base": true, + "inherits": true, + "safe-buffer": true + } + }, + "merge-options": { + "packages": { + "is-plain-obj": true + } + }, + "miller-rabin": { + "packages": { + "bn.js": true, + "brorand": true + } + }, + "mini-create-react-context": { + "packages": { + "@babel/runtime": true, + "gud": true, + "prop-types": true, + "react": true, + "tiny-warning": true + } + }, + "mortice": { + "globals": { + "Worker": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "observable-webworkers": true, + "p-queue": true, + "process": true, + "promise-timeout": true, + "shortid": true + } + }, + "multiaddr": { + "packages": { + "bs58": true, + "buffer": true, + "class-is": true, + "hi-base32": true, + "ip": true, + "is-ip": true, + "varint": true + } + }, + "multiaddr-to-uri": { + "packages": { + "multiaddr": true + } + }, + "multibase": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@multiformats/base-x": true, + "base-x": true, + "buffer": true, + "web-encoding": true + } + }, + "multicodec": { + "packages": { + "buffer": true, + "uint8arrays": true, + "varint": true + } + }, + "multihashes": { + "packages": { + "bs58": true, + "buffer": true, + "multibase": true, + "uint8arrays": true, + "varint": true, + "web-encoding": true + } + }, + "multihashing-async": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "blakejs": true, + "buffer": true, + "err-code": true, + "js-sha3": true, + "multihashes": true, + "murmurhash3js": true, + "murmurhash3js-revisited": true, + "nodeify": true, + "process": true + } + }, + "multistream-select": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "debug": true, + "err-code": true, + "interface-connection": true, + "once": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true, + "semver": true, + "varint": true + } + }, + "muport-did-resolver": { + "packages": { + "@babel/runtime": true, + "did-resolver": true, + "node-fetch": true + } + }, + "murmurhash3js": { + "globals": { + "define": true + } + }, + "murmurhash3js-revisited": { + "globals": { + "define": true + } + }, + "nanoid": { + "globals": { + "crypto": true, + "msCrypto": true, + "navigator": true + }, + "packages": { + "buffer": true, + "crypto-browserify": true + } + }, + "node-forge": { + "globals": { + "Blob": true, + "MutationObserver": true, + "QuotaExceededError": true, + "URL.createObjectURL": true, + "URL.revokeObjectURL": true, + "Worker": true, + "addEventListener": true, + "document": true, + "jQuery": true, + "localStorage": true, + "location": true, + "navigator": true, + "postMessage": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "browser-resolve": true, + "process": true, + "timers-browserify": true + } + }, + "nodeify": { + "globals": { + "setTimeout": true + }, + "packages": { + "is-promise": true, + "process": true, + "promise": true, + "timers-browserify": true + } + }, + "nonce-tracker": { + "packages": { + "assert": true, + "await-semaphore": true, + "ethjs-query": true + } + }, + "number-to-bn": { + "packages": { + "bn.js": true, + "strip-hex-prefix": true + } + }, + "obj-multiplex": { + "globals": { + "console.warn": true + }, + "packages": { + "end-of-stream": true, + "once": true, + "readable-stream": true + } + }, + "obs-store": { + "packages": { + "safe-event-emitter": true, + "xtend": true + } + }, + "once": { + "packages": { + "wrappy": true + } + }, + "orbit-db": { + "globals": { + "console.log": true + }, + "packages": { + "cids": true, + "ipfs-pubsub-1on1": true, + "logplease": true, + "multihashes": true, + "orbit-db-access-controllers": true, + "orbit-db-cache": true, + "orbit-db-counterstore": true, + "orbit-db-docstore": true, + "orbit-db-eventstore": true, + "orbit-db-feedstore": true, + "orbit-db-identity-provider": true, + "orbit-db-io": true, + "orbit-db-keystore": true, + "orbit-db-kvstore": true, + "orbit-db-pubsub": true, + "path-browserify": true + } + }, + "orbit-db-access-controllers": { + "globals": { + "console.log": true + }, + "packages": { + "events": true, + "orbit-db-io": true, + "p-map-series": true, + "path-browserify": true, + "safe-buffer": true + } + }, + "orbit-db-cache": { + "packages": { + "level-js": true, + "logplease": true, + "path-browserify": true + } + }, + "orbit-db-counterstore": { + "packages": { + "crdts": true, + "orbit-db-store": true + } + }, + "orbit-db-docstore": { + "packages": { + "orbit-db-store": true, + "p-map": true, + "readable-stream": true + } + }, + "orbit-db-eventstore": { + "packages": { + "orbit-db-store": true + } + }, + "orbit-db-feedstore": { + "packages": { + "orbit-db-eventstore": true + } + }, + "orbit-db-identity-provider": { + "packages": { + "orbit-db-keystore": true + } + }, + "orbit-db-io": { + "packages": { + "buffer": true, + "cids": true, + "ipld-dag-pb": true + } + }, + "orbit-db-keystore": { + "globals": { + "console.error": true, + "console.log": true + }, + "packages": { + "elliptic": true, + "level-js": true, + "levelup": true, + "libp2p-crypto": true, + "lru": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "orbit-db-kvstore": { + "packages": { + "orbit-db-store": true + } + }, + "orbit-db-pubsub": { + "packages": { + "buffer": true, + "ipfs-pubsub-peer-monitor": true, + "logplease": true, + "p-series": true + } + }, + "orbit-db-store": { + "globals": { + "clearInterval": true, + "console.error": true, + "console.warn": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "events": true, + "ipfs-log": true, + "logplease": true, + "orbit-db-io": true, + "p-each-series": true, + "p-map": true, + "readable-stream": true + } + }, + "os-browserify": { + "globals": { + "location": true, + "navigator": true + } + }, + "p-each-series": { + "packages": { + "p-reduce": true + } + }, + "p-map-series": { + "packages": { + "p-reduce": true + } + }, + "p-queue": { + "globals": { + "clearInterval": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "eventemitter3": true + } + }, + "p-series": { + "packages": { + "@sindresorhus/is": true, + "p-reduce": true + } + }, + "p-times": { + "packages": { + "p-map": true + } + }, + "parse-asn1": { + "packages": { + "asn1.js": true, + "browserify-aes": true, + "buffer": true, + "evp_bytestokey": true, + "pbkdf2": true + } + }, + "path-browserify": { + "packages": { + "process": true + } + }, + "path-to-regexp": { + "packages": { + "isarray": true + } + }, + "pbkdf2": { + "globals": { + "crypto": true, + "process": true + }, + "packages": { + "create-hash": true, + "process": true, + "ripemd160": true, + "safe-buffer": true, + "sha.js": true + } + }, + "peer-book": { + "packages": { + "bs58": true, + "is-buffer": true, + "peer-id": true, + "peer-info": true + } + }, + "peer-id": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "class-is": true, + "libp2p-crypto": true, + "multihashes": true + } + }, + "peer-info": { + "packages": { + "assert": true, + "multiaddr": true, + "peer-id": true, + "unique-by": true + } + }, + "popper.js": { + "globals": { + "MSInputMethodContext": true, + "Node.DOCUMENT_POSITION_FOLLOWING": true, + "cancelAnimationFrame": true, + "console.warn": true, + "define": true, + "devicePixelRatio": true, + "document": true, + "getComputedStyle": true, + "innerHeight": true, + "innerWidth": true, + "navigator": true, + "requestAnimationFrame": true, + "setTimeout": true + } + }, + "precond": { + "packages": { + "util": true + } + }, + "process": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "process-nextick-args": { + "packages": { + "process": true + } + }, + "promise": { + "globals": { + "setImediate": true, + "setTimeout": true + }, + "packages": { + "is-promise": true, + "process": true + } + }, + "promise-timeout": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "promise-to-callback": { + "packages": { + "is-fn": true, + "set-immediate-shim": true + } + }, + "prop-types": { + "globals": { + "console": true + }, + "packages": { + "object-assign": true, + "react-is": true + } + }, + "protons": { + "packages": { + "buffer": true, + "is-buffer": true, + "protocol-buffers-schema": true, + "safe-buffer": true, + "signed-varint": true, + "varint": true + } + }, + "public-encrypt": { + "packages": { + "bn.js": true, + "browserify-rsa": true, + "buffer": true, + "create-hash": true, + "parse-asn1": true, + "randombytes": true + } + }, + "pubnub": { + "globals": { + "ActiveXObject": true, + "XMLHttpRequest": true, + "addEventListener": true, + "btoa": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "define": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "location": true, + "navigator": true, + "setInterval": true, + "setTimeout": true + } + }, + "pull-handshake": { + "packages": { + "pull-cat": true, + "pull-pair": true, + "pull-pushable": true, + "pull-reader": true + } + }, + "pull-length-prefixed": { + "packages": { + "pull-pushable": true, + "pull-reader": true, + "safe-buffer": true, + "varint": true + } + }, + "pull-mplex": { + "packages": { + "async": true, + "buffer": true, + "debug": true, + "events": true, + "interface-connection": true, + "looper": true, + "pull-abortable": true, + "pull-pushable": true, + "pull-stream": true, + "pull-through": true, + "varint": true + } + }, + "pull-reader": { + "globals": { + "cb": true, + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "buffer": true + } + }, + "pull-sort": { + "packages": { + "pull-defer": true, + "pull-stream": true + } + }, + "pull-stream": { + "globals": { + "console.log": true + } + }, + "pull-stream-to-async-iterator": { + "packages": { + "pull-stream": true + } + }, + "pull-stream-to-stream": { + "packages": { + "process": true, + "stream-browserify": true, + "timers-browserify": true + } + }, + "pull-through": { + "packages": { + "looper": true + } + }, + "pull-ws": { + "globals": { + "WebSocket": true, + "location": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "https-browserify": true, + "process": true, + "relative-url": true, + "safe-buffer": true, + "stream-http": true, + "timers-browserify": true, + "url": true + } + }, + "pump": { + "packages": { + "browser-resolve": true, + "end-of-stream": true, + "once": true, + "process": true + } + }, + "punycode": { + "globals": { + "define": true + } + }, + "qrcode-generator": { + "globals": { + "define": true + } + }, + "rabin-wasm": { + "globals": { + "Blob": true, + "Response": true, + "WebAssembly": true + }, + "packages": { + "assemblyscript": true + } + }, + "randombytes": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "process": true, + "safe-buffer": true + } + }, + "randomfill": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "process": true, + "randombytes": true, + "safe-buffer": true + } + }, + "react": { + "globals": { + "console": true + }, + "packages": { + "object-assign": true, + "prop-types": true + } + }, + "react-dnd": { + "globals": { + "console.error": true + }, + "packages": { + "disposables": true, + "dnd-core": true, + "hoist-non-react-statics": true, + "invariant": true, + "lodash": true, + "prop-types": true, + "react": true, + "shallowequal": true + } + }, + "react-dnd-html5-backend": { + "globals": { + "Image": true, + "console.warn": true, + "devicePixelRatio": true, + "document": true, + "navigator.userAgent": true, + "safari": true, + "setTimeout": true + } + }, + "react-dom": { + "globals": { + "MSApp": true, + "__REACT_DEVTOOLS_GLOBAL_HOOK__": true, + "addEventListener": true, + "clearTimeout": true, + "clipboardData": true, + "console": true, + "dispatchEvent": true, + "document": true, + "event": "write", + "jest": true, + "location.protocol": true, + "navigator.userAgent.indexOf": true, + "performance": true, + "removeEventListener": true, + "self": true, + "setTimeout": true, + "top": true, + "trustedTypes": true + }, + "packages": { + "object-assign": true, + "prop-types": true, + "react": true, + "scheduler": true + } + }, + "react-easy-swipe": { + "globals": { + "addEventListener": true, + "define": true, + "document.addEventListener": true, + "document.removeEventListener": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-fast-compare": { + "globals": { + "Element": true, + "console.warn": true + } + }, + "react-idle-timer": { + "globals": { + "clearTimeout": true, + "document": true, + "setTimeout": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-inspector": { + "globals": { + "Node.CDATA_SECTION_NODE": true, + "Node.COMMENT_NODE": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_TYPE_NODE": true, + "Node.ELEMENT_NODE": true, + "Node.PROCESSING_INSTRUCTION_NODE": true, + "Node.TEXT_NODE": true + }, + "packages": { + "babel-runtime": true, + "is-dom": true, + "prop-types": true, + "react": true + } + }, + "react-is": { + "globals": { + "console": true + } + }, + "react-popper": { + "globals": { + "document": true + }, + "packages": { + "@popperjs/core": true, + "react": true, + "react-fast-compare": true, + "warning": true + } + }, + "react-redux": { + "globals": { + "console": true, + "document": true + }, + "packages": { + "@babel/runtime": true, + "hoist-non-react-statics": true, + "prop-types": true, + "react": true, + "react-dom": true, + "react-is": true, + "redux": true + } + }, + "react-responsive-carousel": { + "globals": { + "HTMLElement": true, + "clearTimeout": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "setTimeout": true + }, + "packages": { + "classnames": true, + "react": true, + "react-dom": true, + "react-easy-swipe": true + } + }, + "react-router": { + "packages": { + "history": true, + "hoist-non-react-statics": true, + "mini-create-react-context": true, + "path-to-regexp": true, + "prop-types": true, + "react": true, + "react-is": true, + "tiny-invariant": true, + "tiny-warning": true + } + }, + "react-router-dom": { + "packages": { + "history": true, + "prop-types": true, + "react": true, + "react-router": true, + "tiny-invariant": true, + "tiny-warning": true + } + }, + "react-simple-file-input": { + "globals": { + "File": true, + "FileReader": true, + "console.warn": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-tippy": { + "globals": { + "Element": true, + "MSStream": true, + "MutationObserver": true, + "addEventListener": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "define": true, + "document": true, + "getComputedStyle": true, + "innerHeight": true, + "innerWidth": true, + "navigator.maxTouchPoints": true, + "navigator.msMaxTouchPoints": true, + "navigator.userAgent": true, + "performance": true, + "requestAnimationFrame": true, + "setTimeout": true + }, + "packages": { + "popper.js": true, + "react": true, + "react-dom": true + } + }, + "react-toggle-button": { + "globals": { + "clearTimeout": true, + "console.warn": true, + "define": true, + "performance": true, + "setTimeout": true + }, + "packages": { + "react": true + } + }, + "react-transition-group": { + "globals": { + "Element": true, + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "chain-function": true, + "dom-helpers": true, + "prop-types": true, + "react": true, + "react-dom": true, + "warning": true + } + }, + "readable-stream": { + "packages": { + "browser-resolve": true, + "buffer": true, + "core-util-is": true, + "events": true, + "inherits": true, + "isarray": true, + "process": true, + "process-nextick-args": true, + "safe-buffer": true, + "string_decoder": true, + "timers-browserify": true, + "util-deprecate": true + } + }, + "receptacle": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "ms": true + } + }, + "redux": { + "globals": { + "console": true + }, + "packages": { + "@babel/runtime": true, + "symbol-observable": true + } + }, + "redux-devtools-core": { + "globals": { + "ErrorUtils": true, + "console": true, + "devToolsOptions": true, + "onerror": "write", + "serializeState": true + }, + "packages": { + "get-params": true, + "jsan": true, + "lodash": true, + "nanoid": true, + "remotedev-serialize": true + } + }, + "redux-devtools-instrument": { + "globals": { + "chrome": true, + "console.error": true, + "process": true, + "setTimeout": true + }, + "packages": { + "lodash": true, + "process": true, + "symbol-observable": true + } + }, + "regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "regexp.prototype.flags": { + "packages": { + "define-properties": true, + "es-abstract": true + } + }, + "relative-url": { + "packages": { + "url": true + } + }, + "remote-redux-devtools": { + "globals": { + "console.log": true, + "console.warn": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "jsan": true, + "redux-devtools-core": true, + "redux-devtools-instrument": true, + "rn-host-detect": true, + "socketcluster-client": true + } + }, + "retimer": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "ripemd160": { + "packages": { + "buffer": true, + "hash-base": true, + "inherits": true + } + }, + "rlp": { + "packages": { + "bn.js": true, + "buffer": true + } + }, + "rlp-browser": { + "packages": { + "assert": true, + "buffer": true + } + }, + "rn-host-detect": { + "globals": { + "__DEV__": true, + "__fbBatchedBridgeConfig": true, + "console": true + } + }, + "rpc-cap": { + "packages": { + "@metamask/controllers": true, + "eth-rpc-errors": true, + "is-subset": true, + "json-rpc-engine": true, + "uuid": true + } + }, + "safe-buffer": { + "packages": { + "buffer": true + } + }, + "safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "events": true, + "util": true + } + }, + "sanitize-filename": { + "packages": { + "truncate-utf8-bytes": true + } + }, + "sc-channel": { + "packages": { + "component-emitter": true + } + }, + "sc-formatter": { + "globals": { + "Buffer": true + } + }, + "scheduler": { + "globals": { + "MessageChannel": true, + "cancelAnimationFrame": true, + "clearTimeout": true, + "console": true, + "navigator": true, + "performance": true, + "requestAnimationFrame": true, + "setTimeout": true + } + }, + "scrypt-js": { + "globals": { + "define": true, + "setTimeout": true + }, + "packages": { + "timers-browserify": true + } + }, + "scryptsy": { + "packages": { + "buffer": true, + "pbkdf2": true + } + }, + "secp256k1": { + "packages": { + "bip66": true, + "bn.js": true, + "create-hash": true, + "drbg.js": true, + "elliptic": true, + "is-buffer": true, + "safe-buffer": true + } + }, + "semaphore": { + "globals": { + "define": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "semver": { + "globals": { + "console": true + }, + "packages": { + "process": true + } + }, + "set-immediate-shim": { + "globals": { + "setTimeout.apply": true + }, + "packages": { + "timers-browserify": true + } + }, + "sha.js": { + "packages": { + "inherits": true, + "safe-buffer": true + } + }, + "shortid": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "nanoid": true + } + }, + "signed-varint": { + "packages": { + "varint": true + } + }, + "simple-peer": { + "globals": { + "clearInterval": true, + "console.warn": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "debug": true, + "get-browser-rtc": true, + "inherits": true, + "randombytes": true, + "readable-stream": true + } + }, + "socket.io-client": { + "globals": { + "clearTimeout": true, + "location": true, + "setTimeout": true + }, + "packages": { + "backo2": true, + "component-bind": true, + "component-emitter": true, + "debug": true, + "engine.io-client": true, + "has-binary2": true, + "indexof": true, + "parseqs": true, + "parseuri": true, + "socket.io-parser": true, + "to-array": true + } + }, + "socket.io-parser": { + "globals": { + "Blob": true, + "File": true, + "FileReader": true + }, + "packages": { + "buffer": true, + "component-emitter": true, + "debug": true, + "isarray": true + } + }, + "socket.io-pull-stream": { + "globals": { + "console.error": true + }, + "packages": { + "buffer": true, + "data-queue": true, + "debug": true, + "pull-stream": true, + "uuid": true + } + }, + "socketcluster-client": { + "globals": { + "WebSocket": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "clearTimeout": true, + "localStorage": true, + "location": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "clone": true, + "component-emitter": true, + "linked-list": true, + "querystring-es3": true, + "sc-channel": true, + "sc-errors": true, + "sc-formatter": true, + "uuid": true + } + }, + "sort-keys": { + "packages": { + "is-plain-obj": true + } + }, + "stable": { + "globals": { + "define": true + } + }, + "store": { + "globals": { + "ActiveXObject": true, + "console": true + } + }, + "stream-browserify": { + "packages": { + "events": true, + "inherits": true, + "readable-stream": true + } + }, + "stream-http": { + "globals": { + "AbortController": true, + "Blob": true, + "MSStreamReader": true, + "ReadableStream": true, + "WritableStream": true, + "XDomainRequest": true, + "XMLHttpRequest": true, + "clearTimeout": true, + "fetch": true, + "location.protocol.search": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "builtin-status-codes": true, + "inherits": true, + "process": true, + "readable-stream": true, + "url": true, + "xtend": true + } + }, + "stream-to-pull-stream": { + "globals": { + "console.error": true + }, + "packages": { + "looper": true, + "process": true, + "pull-stream": true + } + }, + "string_decoder": { + "packages": { + "safe-buffer": true + } + }, + "strip-hex-prefix": { + "packages": { + "is-hex-prefixed": true + } + }, + "superagent": { + "globals": { + "ActiveXObject": true, + "XMLHttpRequest": true, + "btoa": true, + "clearTimeout": true, + "console.error": true, + "console.trace": true, + "console.warn": true, + "setTimeout": true + }, + "packages": { + "component-emitter": true + } + }, + "textarea-caret": { + "globals": { + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true, + "document.querySelector": true, + "getCaretCoordinates": "write", + "getComputedStyle": true, + "mozInnerScreenX": true + } + }, + "through": { + "packages": { + "process": true, + "stream-browserify": true + } + }, + "through2": { + "packages": { + "process": true, + "readable-stream": true, + "util": true, + "xtend": true + } + }, + "time-cache": { + "packages": { + "lodash.throttle": true + } + }, + "timers-browserify": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "tiny-warning": { + "globals": { + "console": true + } + }, + "toggle-selection": { + "globals": { + "document.activeElement": true, + "document.getSelection": true + } + }, + "trezor-connect": { + "globals": { + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "fetch": true, + "location": true, + "navigator": true, + "open": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "events": true, + "whatwg-fetch": true + } + }, + "truncate-utf8-bytes": { + "packages": { + "utf8-byte-length": true + } + }, + "tslib": { + "globals": { + "define": true + } + }, + "tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browser-resolve": true + } + }, + "tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browser-resolve": true + } + }, + "typedarray-to-buffer": { + "packages": { + "buffer": true, + "is-typedarray": true + } + }, + "typical": { + "globals": { + "define": true + } + }, + "uint8arrays": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "multibase": true, + "web-encoding": true + } + }, + "unorm": { + "globals": { + "define": true + } + }, + "uport-base64url": { + "packages": { + "buffer": true + } + }, + "url": { + "packages": { + "punycode": true, + "querystring-es3": true + } + }, + "utf8": { + "globals": { + "define": true + } + }, + "util": { + "globals": { + "console.error": true, + "console.log": true, + "console.trace": true, + "process": true + }, + "packages": { + "inherits": true, + "process": true + } + }, + "util-deprecate": { + "globals": { + "console.trace": true, + "console.warn": true, + "localStorage": true + } + }, + "uuid": { + "globals": { + "crypto": true, + "msCrypto": true + } + }, + "varint-decoder": { + "packages": { + "is-buffer": true, + "varint": true + } + }, + "vm-browserify": { + "globals": { + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true + } + }, + "warning": { + "globals": { + "console": true + } + }, + "web-encoding": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "util": true + } + }, + "web3": { + "globals": { + "Web3": "write", + "XMLHttpRequest": "write", + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "bignumber.js": true, + "buffer": true, + "crypto-js": true, + "utf8": true, + "xhr2-cookies": true + } + }, + "web3-provider-engine": { + "globals": { + "WebSocket": true, + "console": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx": true, + "async": true, + "backoff": true, + "browser-resolve": true, + "buffer": true, + "eth-block-tracker": true, + "eth-json-rpc-filters": true, + "eth-json-rpc-infura": true, + "eth-json-rpc-middleware": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "events": true, + "json-stable-stringify": true, + "semaphore": true, + "util": true, + "xtend": true + } + }, + "web3-stream-provider": { + "globals": { + "setTimeout": true + }, + "packages": { + "readable-stream": true, + "util": true, + "uuid": true + } + }, + "webrtcsupport": { + "globals": { + "AudioContext": true, + "MediaStream": true, + "RTCIceCandidate": true, + "RTCPeerConnection": true, + "RTCSessionDescription": true, + "document": true, + "location.protocol": true, + "mozRTCIceCandidate": true, + "mozRTCPeerConnection": true, + "mozRTCSessionDescription": true, + "navigator.getUserMedia": true, + "navigator.mozGetUserMedia": true, + "navigator.msGetUserMedia": true, + "navigator.userAgent.match": true, + "navigator.webkitGetUserMedia": true, + "webkitAudioContext": true, + "webkitMediaStream": true, + "webkitRTCPeerConnection": true + } + }, + "whatwg-fetch": { + "globals": { + "Blob": true, + "FileReader": true, + "FormData": true, + "URLSearchParams.prototype.isPrototypeOf": true, + "XMLHttpRequest": true, + "define": true, + "setTimeout": true + } + }, + "xhr2": { + "globals": { + "XMLHttpRequest": true + } + }, + "xhr2-cookies": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "cookiejar": true, + "https-browserify": true, + "os-browserify": true, + "process": true, + "stream-http": true, + "url": true + } + }, + "xor-distance": { + "packages": { + "buffer": true + } + } + } +} \ No newline at end of file diff --git a/lavamoat/browserify/main/policy-override.json b/lavamoat/browserify/main/policy-override.json new file mode 100644 index 000000000..71fd98f61 --- /dev/null +++ b/lavamoat/browserify/main/policy-override.json @@ -0,0 +1,55 @@ +{ + "resources": { + "browser-resolve": { + "packages": { + "core-js": true + } + }, + "babel-runtime": { + "packages": { + "@babel/runtime": true + } + }, + "node-fetch": { + "globals": { + "fetch": true + } + }, + "lodash": { + "globals": { + "setTimeout": true, + "clearTimeout": true + } + }, + "@ethersproject/random": { + "globals": { + "crypto.getRandomValues": true + } + }, + "browser-passworder": { + "globals": { + "crypto": true + } + }, + "randombytes": { + "globals": { + "crypto.getRandomValues": true + } + }, + "extensionizer": { + "globals": { + "console": true + } + }, + "web3": { + "globals": { + "XMLHttpRequest": true + } + }, + "storage": { + "globals": { + "localStorage": true + } + } + } +} diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json new file mode 100644 index 000000000..3cfd712fa --- /dev/null +++ b/lavamoat/browserify/main/policy.json @@ -0,0 +1,4772 @@ +{ + "resources": { + "3box": { + "globals": { + "console.error": true, + "console.log": true, + "console.warn": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "3box-orbitdb-plugins": true, + "3id-resolver": true, + "@babel/runtime": true, + "buffer": true, + "did-jwt": true, + "elliptic": true, + "ethers": true, + "graphql-request": true, + "https-did-resolver": true, + "ipfs": true, + "ipfs-did-document": true, + "ipfs-log": true, + "ipfs-mini": true, + "is-ipfs": true, + "js-sha256": true, + "multihashes": true, + "muport-did-resolver": true, + "node-fetch": true, + "orbit-db": true, + "orbit-db-access-controllers": true, + "orbit-db-identity-provider": true, + "orbit-db-pubsub": true, + "process": true, + "store": true, + "tweetnacl": true, + "tweetnacl-util": true + } + }, + "3box-orbitdb-plugins": { + "globals": { + "console.log": true + }, + "packages": { + "base64url": true, + "did-jwt": true, + "did-resolver": true, + "events": true, + "ipfs-log": true, + "is-ipfs": true, + "orbit-db-access-controllers": true, + "orbit-db-io": true, + "safe-buffer": true + } + }, + "3id-resolver": { + "packages": { + "@babel/runtime": true, + "base64url": true, + "did-jwt": true, + "did-resolver": true, + "ipfs-did-document": true + } + }, + "@babel/runtime": { + "packages": { + "regenerator-runtime": true + } + }, + "@download/blockies": { + "globals": { + "document.createElement": true + } + }, + "@ensdomains/content-hash": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "cids": true, + "js-base64": true, + "multicodec": true, + "multihashes": true + } + }, + "@eth-optimism/contracts": { + "packages": { + "@ethersproject/abstract-provider": true, + "ethers": true + } + }, + "@ethereumjs/common": { + "packages": { + "buffer": true, + "crc-32": true, + "ethereumjs-util": true, + "events": true + } + }, + "@ethereumjs/tx": { + "packages": { + "@ethereumjs/common": true, + "buffer": true, + "ethereumjs-util": true, + "is-buffer": true + } + }, + "@ethersproject/abi": { + "globals": { + "console.log": true + }, + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/hash": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/abstract-provider": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/abstract-signer": { + "packages": { + "@ethersproject/logger": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/address": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/rlp": true + } + }, + "@ethersproject/base64": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "@ethersproject/bytes": true + } + }, + "@ethersproject/basex": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/properties": true + } + }, + "@ethersproject/bignumber": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "bn.js": true + } + }, + "@ethersproject/bytes": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/constants": { + "packages": { + "@ethersproject/bignumber": true + } + }, + "@ethersproject/contracts": { + "globals": { + "setTimeout": true + }, + "packages": { + "@ethersproject/abi": true, + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/transactions": true + } + }, + "@ethersproject/hash": { + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/hdnode": { + "packages": { + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/pbkdf2": true, + "@ethersproject/properties": true, + "@ethersproject/sha2": true, + "@ethersproject/signing-key": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/wordlists": true + } + }, + "@ethersproject/json-wallets": { + "packages": { + "@ethersproject/address": true, + "@ethersproject/bytes": true, + "@ethersproject/hdnode": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/pbkdf2": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "aes-js": true, + "scrypt-js": true + } + }, + "@ethersproject/keccak256": { + "packages": { + "@ethersproject/bytes": true, + "js-sha3": true + } + }, + "@ethersproject/logger": { + "globals": { + "console": true + } + }, + "@ethersproject/networks": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/pbkdf2": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/sha2": true + } + }, + "@ethersproject/properties": { + "packages": { + "@ethersproject/logger": true + } + }, + "@ethersproject/providers": { + "globals": { + "WebSocket": true, + "clearInterval": true, + "clearTimeout": true, + "console.log": true, + "console.warn": true, + "name": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/hash": true, + "@ethersproject/logger": true, + "@ethersproject/networks": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/sha2": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/web": true, + "bech32": true + } + }, + "@ethersproject/random": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/rlp": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/sha2": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "hash.js": true + } + }, + "@ethersproject/signing-key": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "elliptic": true + } + }, + "@ethersproject/solidity": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/sha2": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/strings": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/transactions": { + "globals": { + "console.log": true + }, + "packages": { + "@ethersproject/address": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/rlp": true, + "@ethersproject/signing-key": true + } + }, + "@ethersproject/units": { + "packages": { + "@ethersproject/bignumber": true, + "@ethersproject/logger": true + } + }, + "@ethersproject/wallet": { + "packages": { + "@ethersproject/abstract-provider": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/bytes": true, + "@ethersproject/hash": true, + "@ethersproject/hdnode": true, + "@ethersproject/json-wallets": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/random": true, + "@ethersproject/signing-key": true, + "@ethersproject/transactions": true + } + }, + "@ethersproject/web": { + "globals": { + "clearTimeout": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/base64": true, + "@ethersproject/bytes": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@ethersproject/wordlists": { + "packages": { + "@ethersproject/bytes": true, + "@ethersproject/hash": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/strings": true + } + }, + "@formatjs/intl-relativetimeformat": { + "globals": { + "Intl": true + }, + "packages": { + "@formatjs/intl-utils": true + } + }, + "@formatjs/intl-utils": { + "globals": { + "Intl.getCanonicalLocales": true + } + }, + "@material-ui/core": { + "globals": { + "Image": true, + "_formatMuiErrorMessage": true, + "addEventListener": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "getSelection": true, + "innerHeight": true, + "innerWidth": true, + "matchMedia": true, + "navigator": true, + "performance.now": true, + "removeEventListener": true, + "requestAnimationFrame": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/styles": true, + "@material-ui/system": true, + "@material-ui/utils": true, + "clsx": true, + "hoist-non-react-statics": true, + "popper.js": true, + "prop-types": true, + "react": true, + "react-dom": true, + "react-is": true, + "react-transition-group": true + } + }, + "@material-ui/styles": { + "globals": { + "console.error": true, + "console.warn": true, + "document.createComment": true, + "document.head": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/utils": true, + "clsx": true, + "hoist-non-react-statics": true, + "jss": true, + "jss-plugin-camel-case": true, + "jss-plugin-default-unit": true, + "jss-plugin-global": true, + "jss-plugin-nested": true, + "jss-plugin-props-sort": true, + "jss-plugin-rule-value-function": true, + "jss-plugin-vendor-prefixer": true, + "prop-types": true, + "react": true + } + }, + "@material-ui/system": { + "globals": { + "console.error": true + }, + "packages": { + "@babel/runtime": true, + "@material-ui/utils": true, + "prop-types": true + } + }, + "@material-ui/utils": { + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react-is": true + } + }, + "@metamask/controllers": { + "globals": { + "Headers": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "@metamask/contract-metadata": true, + "abort-controller": true, + "async-mutex": true, + "await-semaphore": true, + "buffer": true, + "eth-ens-namehash": true, + "eth-json-rpc-infura": true, + "eth-keyring-controller": true, + "eth-method-registry": true, + "eth-phishing-detect": true, + "eth-query": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "ethereumjs-tx": true, + "ethereumjs-util": true, + "ethereumjs-wallet": true, + "ethers": true, + "ethjs-query": true, + "ethjs-unit": true, + "ethjs-util": true, + "events": true, + "human-standard-collectible-abi": true, + "human-standard-token-abi": true, + "immer": true, + "isomorphic-fetch": true, + "jsonschema": true, + "nanoid": true, + "punycode": true, + "single-call-balance-checker-abi": true, + "uuid": true, + "web3": true, + "web3-provider-engine": true + } + }, + "@metamask/eth-ledger-bridge-keyring": { + "globals": { + "addEventListener": true, + "console.log": true, + "document.createElement": true, + "document.head.appendChild": true, + "fetch": true, + "removeEventListener": true + }, + "packages": { + "@ethereumjs/tx": true, + "buffer": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "events": true, + "hdkey": true + } + }, + "@metamask/eth-token-tracker": { + "globals": { + "console.warn": true + }, + "packages": { + "@babel/runtime": true, + "deep-equal": true, + "eth-block-tracker": true, + "ethjs": true, + "ethjs-contract": true, + "ethjs-query": true, + "human-standard-token-abi": true, + "safe-event-emitter": true + } + }, + "@metamask/etherscan-link": { + "globals": { + "URL": true + } + }, + "@metamask/jazzicon": { + "globals": { + "document.createElement": true, + "document.createElementNS": true + }, + "packages": { + "color": true, + "mersenne-twister": true + } + }, + "@metamask/logo": { + "globals": { + "addEventListener": true, + "document.body.appendChild": true, + "document.createElementNS": true, + "innerHeight": true, + "innerWidth": true, + "requestAnimationFrame": true + }, + "packages": { + "gl-mat4": true, + "gl-vec3": true + } + }, + "@metamask/obs-store": { + "globals": { + "localStorage": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "stream-browserify": true, + "through2": true + } + }, + "@metamask/safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "events": true + } + }, + "@popperjs/core": { + "globals": { + "Element": true, + "HTMLElement": true, + "ShadowRoot": true, + "console.error": true, + "console.warn": true, + "document": true, + "navigator.userAgent": true + } + }, + "@reduxjs/toolkit": { + "globals": { + "AbortController": true, + "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__": true, + "__REDUX_DEVTOOLS_EXTENSION__": true, + "console.error": true, + "console.info": true, + "console.warn": true + }, + "packages": { + "immer": true, + "redux": true, + "redux-thunk": true, + "reselect": true + } + }, + "@segment/loosely-validate-event": { + "packages": { + "assert": true, + "buffer": true, + "component-type": true, + "join-component": true + } + }, + "@sentry/browser": { + "globals": { + "XMLHttpRequest": true, + "setTimeout": true + }, + "packages": { + "@sentry/core": true, + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/core": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@sentry/hub": true, + "@sentry/minimal": true, + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/hub": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "tslib": true + } + }, + "@sentry/integrations": { + "globals": { + "clearTimeout": true, + "console.error": true, + "console.log": true, + "setTimeout": true + }, + "packages": { + "@sentry/types": true, + "@sentry/utils": true, + "localforage": true, + "tslib": true + } + }, + "@sentry/minimal": { + "packages": { + "@sentry/hub": true, + "tslib": true + } + }, + "@sentry/utils": { + "globals": { + "CustomEvent": true, + "DOMError": true, + "DOMException": true, + "Element": true, + "ErrorEvent": true, + "Event": true, + "Headers": true, + "Request": true, + "Response": true, + "XMLHttpRequest.prototype": true, + "clearTimeout": true, + "console.error": true, + "document": true, + "setTimeout": true + }, + "packages": { + "process": true, + "tslib": true + } + }, + "@sindresorhus/is": { + "packages": { + "is-buffer": true, + "util": true + } + }, + "@zxing/library": { + "globals": { + "TextDecoder": true, + "TextEncoder": true, + "btoa": true, + "clearTimeout": true, + "define": true, + "document.createElement": true, + "document.createElementNS": true, + "document.getElementById": true, + "navigator.mediaDevices.enumerateDevices": true, + "navigator.mediaDevices.getUserMedia": true, + "setTimeout": true + } + }, + "abort-controller": { + "globals": { + "AbortController": true + } + }, + "abstract-leveldown": { + "packages": { + "is-buffer": true, + "process": true, + "xtend": true + } + }, + "accounting": { + "globals": { + "define": true + } + }, + "aes-js": { + "globals": { + "define": true + } + }, + "analytics-node": { + "globals": { + "clearTimeout": true, + "console.log": true, + "setImmediate": true, + "setTimeout": true + }, + "packages": { + "@segment/loosely-validate-event": true, + "assert": true, + "axios": true, + "axios-retry": true, + "lodash.isstring": true, + "md5": true, + "ms": true, + "process": true, + "remove-trailing-slash": true, + "uuid": true + } + }, + "asap": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "document.createTextNode": true, + "setInterval": true, + "setTimeout": true + } + }, + "asn1.js": { + "packages": { + "bn.js": true, + "buffer": true, + "inherits": true, + "minimalistic-assert": true, + "vm-browserify": true + } + }, + "assemblyscript": { + "globals": { + "WebAssembly.Instance": true, + "WebAssembly.Module": true, + "WebAssembly.instantiateStreaming": true, + "console.log": true + } + }, + "assert": { + "globals": { + "Buffer": true + }, + "packages": { + "object-assign": true, + "util": true + } + }, + "async": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "lodash": true, + "process": true, + "timers-browserify": true + } + }, + "async-iterator-to-pull-stream": { + "packages": { + "get-iterator": true, + "pull-stream-to-async-iterator": true + } + }, + "async-iterator-to-stream": { + "packages": { + "process": true, + "readable-stream": true + } + }, + "async-mutex": { + "globals": { + "setTimeout": true + }, + "packages": { + "tslib": true + } + }, + "await-semaphore": { + "packages": { + "process": true, + "timers-browserify": true + } + }, + "axios": { + "globals": { + "FormData": true, + "URLSearchParams": true, + "XMLHttpRequest": true, + "btoa": true, + "console.warn": true, + "document": true, + "location.href": true, + "navigator": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "axios-retry": { + "globals": { + "setTimeout": true + }, + "packages": { + "is-retry-allowed": true + } + }, + "babel-runtime": { + "packages": { + "core-js": true, + "regenerator-runtime": true + } + }, + "backoff": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "events": true, + "precond": true, + "util": true + } + }, + "base-x": { + "packages": { + "safe-buffer": true + } + }, + "base32-encode": { + "packages": { + "to-data-view": true + } + }, + "base64url": { + "packages": { + "buffer": true + } + }, + "bignumber.js": { + "globals": { + "crypto": true, + "define": true + }, + "packages": { + "crypto-browserify": true + } + }, + "bip39": { + "packages": { + "create-hash": true, + "pbkdf2": true, + "randombytes": true, + "safe-buffer": true, + "unorm": true + } + }, + "bip66": { + "packages": { + "safe-buffer": true + } + }, + "bitwise": { + "packages": { + "buffer": true + } + }, + "bl": { + "packages": { + "buffer": true, + "readable-stream": true, + "util": true + } + }, + "blakejs": { + "globals": { + "console.log": true + }, + "packages": { + "buffer": true + } + }, + "blob": { + "globals": { + "Blob": true, + "MSBlobBuilder": true, + "MozBlobBuilder": true, + "WebKitBlobBuilder": true + } + }, + "bn.js": { + "packages": { + "browser-resolve": true + } + }, + "borc": { + "globals": { + "console": true + }, + "packages": { + "bignumber.js": true, + "buffer": true, + "ieee754": true, + "iso-url": true + } + }, + "brorand": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "browser-resolve": true + } + }, + "browser-passworder": { + "globals": { + "btoa": true, + "crypto.getRandomValues": true, + "crypto.subtle.decrypt": true, + "crypto.subtle.deriveKey": true, + "crypto.subtle.encrypt": true, + "crypto.subtle.importKey": true + }, + "packages": { + "browserify-unibabel": true + } + }, + "browserify-aes": { + "packages": { + "buffer": true, + "buffer-xor": true, + "cipher-base": true, + "evp_bytestokey": true, + "inherits": true, + "safe-buffer": true + } + }, + "browserify-cipher": { + "packages": { + "browserify-aes": true, + "browserify-des": true, + "evp_bytestokey": true + } + }, + "browserify-des": { + "packages": { + "buffer": true, + "cipher-base": true, + "des.js": true, + "inherits": true + } + }, + "browserify-rsa": { + "packages": { + "bn.js": true, + "buffer": true, + "randombytes": true + } + }, + "browserify-sign": { + "packages": { + "bn.js": true, + "browserify-rsa": true, + "buffer": true, + "create-hash": true, + "create-hmac": true, + "elliptic": true, + "inherits": true, + "parse-asn1": true, + "stream-browserify": true + } + }, + "browserify-unibabel": { + "globals": { + "atob": true, + "btoa": true + } + }, + "bs58": { + "packages": { + "base-x": true + } + }, + "bs58check": { + "packages": { + "bs58": true, + "create-hash": true, + "safe-buffer": true + } + }, + "btoa": { + "packages": { + "buffer": true + } + }, + "buffer": { + "globals": { + "console": true + }, + "packages": { + "base64-js": true, + "ieee754": true + } + }, + "buffer-split": { + "packages": { + "buffer-indexof": true + } + }, + "buffer-xor": { + "packages": { + "buffer": true + } + }, + "cids": { + "packages": { + "buffer": true, + "class-is": true, + "is-buffer": true, + "multibase": true, + "multicodec": true, + "multihashes": true, + "uint8arrays": true + } + }, + "cipher-base": { + "packages": { + "inherits": true, + "safe-buffer": true, + "stream-browserify": true, + "string_decoder": true + } + }, + "classnames": { + "globals": { + "classNames": "write", + "define": true + } + }, + "clone": { + "packages": { + "buffer": true + } + }, + "coinstring": { + "packages": { + "bs58": true, + "buffer": true, + "create-hash": true + } + }, + "color": { + "packages": { + "clone": true, + "color-convert": true, + "color-string": true + } + }, + "color-convert": { + "packages": { + "color-name": true + } + }, + "color-string": { + "packages": { + "color-name": true + } + }, + "cookiejar": { + "globals": { + "console.warn": true + } + }, + "copy-to-clipboard": { + "globals": { + "clipboardData.setData": true, + "console.error": true, + "console.warn": true, + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true, + "document.createRange": true, + "document.execCommand": true, + "document.getSelection": true, + "navigator.userAgent": true, + "prompt": true + }, + "packages": { + "toggle-selection": true + } + }, + "core-js": { + "globals": { + "PromiseRejectionEvent": true, + "__e": "write", + "__g": "write", + "document.createTextNode": true, + "postMessage": true, + "setTimeout": true + } + }, + "core-util-is": { + "packages": { + "is-buffer": true + } + }, + "crc-32": { + "globals": { + "DO_NOT_EXPORT_CRC": true, + "define": true + } + }, + "create-ecdh": { + "packages": { + "bn.js": true, + "buffer": true, + "elliptic": true + } + }, + "create-hash": { + "packages": { + "cipher-base": true, + "inherits": true, + "md5.js": true, + "ripemd160": true, + "sha.js": true + } + }, + "create-hmac": { + "packages": { + "cipher-base": true, + "create-hash": true, + "inherits": true, + "ripemd160": true, + "safe-buffer": true, + "sha.js": true + } + }, + "cross-fetch": { + "globals": { + "Blob": true, + "FileReader": true, + "FormData": true, + "URLSearchParams.prototype.isPrototypeOf": true, + "XMLHttpRequest": true + } + }, + "crypto-browserify": { + "packages": { + "browserify-cipher": true, + "browserify-sign": true, + "create-ecdh": true, + "create-hash": true, + "create-hmac": true, + "diffie-hellman": true, + "pbkdf2": true, + "public-encrypt": true, + "randombytes": true, + "randomfill": true + } + }, + "crypto-js": { + "globals": { + "define": true + } + }, + "css-vendor": { + "globals": { + "document.createElement": true, + "document.documentElement": true, + "getComputedStyle": true + }, + "packages": { + "@babel/runtime": true, + "is-in-browser": true + } + }, + "currency-formatter": { + "packages": { + "accounting": true, + "locale-currency": true, + "object-assign": true + } + }, + "data-queue": { + "packages": { + "events": true + } + }, + "datastore-core": { + "packages": { + "async": true, + "buffer": true, + "interface-datastore": true, + "pull-many": true, + "pull-stream": true + } + }, + "datastore-level": { + "packages": { + "buffer": true, + "encoding-down": true, + "interface-datastore": true, + "level-js": true, + "levelup": true, + "pull-stream": true + } + }, + "datastore-pubsub": { + "packages": { + "assert": true, + "buffer": true, + "debug": true, + "err-code": true, + "interface-datastore": true, + "multibase": true + } + }, + "debounce": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "debounce-stream": { + "packages": { + "debounce": true, + "duplexer": true, + "through": true + } + }, + "debug": { + "globals": { + "chrome": true, + "console": true, + "document": true, + "localStorage": true, + "navigator": true, + "process": true + }, + "packages": { + "ms": true, + "process": true + } + }, + "deep-equal": { + "packages": { + "is-arguments": true, + "is-date-object": true, + "is-regex": true, + "object-is": true, + "object-keys": true, + "regexp.prototype.flags": true + } + }, + "deep-extend": { + "packages": { + "buffer": true + } + }, + "deferred-leveldown": { + "packages": { + "abstract-leveldown": true, + "inherits": true + } + }, + "define-properties": { + "packages": { + "object-keys": true + } + }, + "des.js": { + "packages": { + "inherits": true, + "minimalistic-assert": true + } + }, + "did-jwt": { + "packages": { + "@babel/runtime": true, + "@stablelib/utf8": true, + "base64url": true, + "buffer": true, + "did-resolver": true, + "elliptic": true, + "js-sha256": true, + "js-sha3": true, + "tweetnacl": true, + "tweetnacl-util": true, + "uport-base64url": true + } + }, + "diffie-hellman": { + "packages": { + "bn.js": true, + "buffer": true, + "miller-rabin": true, + "randombytes": true + } + }, + "dlv": { + "globals": { + "define": true + } + }, + "dnd-core": { + "packages": { + "asap": true, + "invariant": true, + "lodash": true, + "redux": true + } + }, + "dom-helpers": { + "globals": { + "document": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true + } + }, + "drbg.js": { + "packages": { + "buffer": true, + "create-hmac": true + } + }, + "duplexer": { + "packages": { + "stream-browserify": true + } + }, + "elliptic": { + "packages": { + "bn.js": true, + "brorand": true, + "hash.js": true, + "hmac-drbg": true, + "inherits": true, + "minimalistic-assert": true, + "minimalistic-crypto-utils": true + } + }, + "encoding-down": { + "packages": { + "abstract-leveldown": true, + "inherits": true, + "level-codec": true, + "level-errors": true + } + }, + "end-of-stream": { + "packages": { + "once": true, + "process": true + } + }, + "engine.io-client": { + "globals": { + "MozWebSocket": true, + "WebSocket": true, + "XDomainRequest": true, + "XMLHttpRequest": true, + "addEventListener": true, + "attachEvent": true, + "clearTimeout": true, + "document": true, + "location": true, + "navigator": true, + "setTimeout": true + }, + "packages": { + "browser-resolve": true, + "buffer": true, + "component-emitter": true, + "component-inherit": true, + "debug": true, + "engine.io-parser": true, + "has-cors": true, + "indexof": true, + "parseqs": true, + "parseuri": true, + "yeast": true + } + }, + "engine.io-parser": { + "globals": { + "FileReader": true, + "btoa": true, + "navigator": true + }, + "packages": { + "after": true, + "arraybuffer.slice": true, + "base64-arraybuffer": true, + "blob": true, + "has-binary2": true + } + }, + "errno": { + "packages": { + "prr": true + } + }, + "es-abstract": { + "packages": { + "function-bind": true, + "has-symbols": true + } + }, + "eth-block-tracker": { + "globals": { + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "eth-query": true, + "json-rpc-random-id": true, + "pify": true, + "safe-event-emitter": true + } + }, + "eth-ens-namehash": { + "globals": { + "name": "write" + }, + "packages": { + "buffer": true, + "idna-uts46": true, + "idna-uts46-hx": true, + "js-sha3": true + } + }, + "eth-hd-keyring": { + "packages": { + "bip39": true, + "eth-sig-util": true, + "eth-simple-keyring": true, + "ethereumjs-wallet": true + } + }, + "eth-json-rpc-filters": { + "globals": { + "console.error": true, + "results": "write" + }, + "packages": { + "await-semaphore": true, + "eth-json-rpc-middleware": true, + "eth-query": true, + "json-rpc-engine": true, + "lodash.flatmap": true, + "pify": true, + "safe-event-emitter": true + } + }, + "eth-json-rpc-infura": { + "globals": { + "setTimeout": true + }, + "packages": { + "eth-json-rpc-middleware": true, + "eth-rpc-errors": true, + "json-rpc-engine": true, + "node-fetch": true + } + }, + "eth-json-rpc-middleware": { + "globals": { + "URL": true, + "btoa": true, + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/safe-event-emitter": true, + "browser-resolve": true, + "btoa": true, + "clone": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "json-rpc-engine": true, + "json-stable-stringify": true, + "node-fetch": true, + "pify": true, + "safe-event-emitter": true, + "url": true + } + }, + "eth-keyring-controller": { + "packages": { + "bip39": true, + "browser-passworder": true, + "eth-hd-keyring": true, + "eth-sig-util": true, + "eth-simple-keyring": true, + "ethereumjs-util": true, + "events": true, + "loglevel": true, + "obs-store": true + } + }, + "eth-lattice-keyring": { + "globals": { + "addEventListener": true, + "browser": true, + "clearInterval": true, + "console.warn": true, + "open": true, + "setInterval": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "bignumber.js": true, + "buffer": true, + "crypto-browserify": true, + "ethereumjs-util": true, + "events": true, + "gridplus-sdk": true + } + }, + "eth-method-registry": { + "packages": { + "ethjs": true + } + }, + "eth-phishing-detect": { + "packages": { + "fast-levenshtein": true + } + }, + "eth-query": { + "packages": { + "json-rpc-random-id": true, + "xtend": true + } + }, + "eth-rpc-errors": { + "packages": { + "fast-safe-stringify": true + } + }, + "eth-sig-util": { + "packages": { + "buffer": true, + "ethereumjs-abi": true, + "ethereumjs-util": true, + "tweetnacl": true, + "tweetnacl-util": true + } + }, + "eth-simple-keyring": { + "packages": { + "buffer": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "ethereumjs-wallet": true, + "events": true + } + }, + "eth-trezor-keyring": { + "globals": { + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx": true, + "buffer": true, + "ethereumjs-util": true, + "events": true, + "hdkey": true, + "trezor-connect": true + } + }, + "ethereum-cryptography": { + "packages": { + "assert": true, + "bs58check": true, + "buffer": true, + "create-hmac": true, + "hash.js": true, + "keccak": true, + "randombytes": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "ethereumjs-abi": { + "packages": { + "bn.js": true, + "buffer": true, + "ethereumjs-util": true + } + }, + "ethereumjs-tx": { + "packages": { + "buffer": true, + "ethereum-common": true, + "ethereumjs-util": true + } + }, + "ethereumjs-util": { + "packages": { + "assert": true, + "bn.js": true, + "buffer": true, + "create-hash": true, + "elliptic": true, + "ethereum-cryptography": true, + "ethjs-util": true, + "is-buffer": true, + "keccak": true, + "rlp": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "ethereumjs-wallet": { + "packages": { + "aes-js": true, + "bs58check": true, + "buffer": true, + "crypto-browserify": true, + "ethereum-cryptography": true, + "ethereumjs-util": true, + "randombytes": true, + "safe-buffer": true, + "scrypt-js": true, + "scryptsy": true, + "utf8": true, + "uuid": true + } + }, + "ethers": { + "globals": { + "MessageChannel": true, + "XMLHttpRequest": true, + "atob": true, + "btoa": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "crypto.getRandomValues": true, + "define": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethersproject/abi": true, + "@ethersproject/abstract-signer": true, + "@ethersproject/address": true, + "@ethersproject/base64": true, + "@ethersproject/basex": true, + "@ethersproject/bignumber": true, + "@ethersproject/bytes": true, + "@ethersproject/constants": true, + "@ethersproject/contracts": true, + "@ethersproject/hash": true, + "@ethersproject/hdnode": true, + "@ethersproject/json-wallets": true, + "@ethersproject/keccak256": true, + "@ethersproject/logger": true, + "@ethersproject/properties": true, + "@ethersproject/providers": true, + "@ethersproject/random": true, + "@ethersproject/rlp": true, + "@ethersproject/sha2": true, + "@ethersproject/signing-key": true, + "@ethersproject/solidity": true, + "@ethersproject/strings": true, + "@ethersproject/transactions": true, + "@ethersproject/units": true, + "@ethersproject/wallet": true, + "@ethersproject/web": true, + "@ethersproject/wordlists": true + } + }, + "ethers-eip712": { + "packages": { + "ethers": true + } + }, + "ethjs": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "bn.js": true, + "buffer": true, + "ethjs-abi": true, + "ethjs-contract": true, + "ethjs-filter": true, + "ethjs-provider-http": true, + "ethjs-query": true, + "ethjs-unit": true, + "ethjs-util": true, + "js-sha3": true, + "number-to-bn": true + } + }, + "ethjs-abi": { + "packages": { + "bn.js": true, + "buffer": true, + "js-sha3": true, + "number-to-bn": true + } + }, + "ethjs-contract": { + "packages": { + "babel-runtime": true, + "ethjs-abi": true, + "ethjs-filter": true, + "ethjs-util": true, + "js-sha3": true, + "promise-to-callback": true + } + }, + "ethjs-ens": { + "packages": { + "eth-ens-namehash": true, + "ethereum-ens-network-map": true, + "ethjs-contract": true, + "ethjs-query": true + } + }, + "ethjs-filter": { + "globals": { + "clearInterval": true, + "setInterval": true + } + }, + "ethjs-format": { + "packages": { + "ethjs-schema": true, + "ethjs-util": true, + "number-to-bn": true, + "strip-hex-prefix": true + } + }, + "ethjs-provider-http": { + "packages": { + "xhr2": true + } + }, + "ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "babel-runtime": true, + "ethjs-format": true, + "ethjs-rpc": true, + "promise-to-callback": true + } + }, + "ethjs-rpc": { + "packages": { + "promise-to-callback": true + } + }, + "ethjs-unit": { + "packages": { + "bn.js": true, + "number-to-bn": true + } + }, + "ethjs-util": { + "packages": { + "buffer": true, + "is-hex-prefixed": true, + "strip-hex-prefix": true + } + }, + "events": { + "globals": { + "console": true + } + }, + "evp_bytestokey": { + "packages": { + "md5.js": true, + "safe-buffer": true + } + }, + "extension-port-stream": { + "packages": { + "buffer": true, + "stream-browserify": true + } + }, + "extensionizer": { + "globals": { + "browser": true, + "chrome": true + } + }, + "fast-json-patch": { + "globals": { + "addEventListener": true, + "clearTimeout": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "fast-deep-equal": true + } + }, + "fast-levenshtein": { + "globals": { + "Intl": true, + "Levenshtein": "write", + "console.log": true, + "define": true, + "importScripts": true, + "postMessage": true + } + }, + "fsm-event": { + "packages": { + "assert": true, + "events": true, + "fsm": true + } + }, + "fuse.js": { + "globals": { + "console": true, + "define": true + } + }, + "get-browser-rtc": { + "globals": { + "RTCIceCandidate": true, + "RTCPeerConnection": true, + "RTCSessionDescription": true, + "mozRTCIceCandidate": true, + "mozRTCPeerConnection": true, + "mozRTCSessionDescription": true, + "webkitRTCIceCandidate": true, + "webkitRTCPeerConnection": true, + "webkitRTCSessionDescription": true + } + }, + "get-params": { + "globals": { + "GetParams": "write" + } + }, + "graphql-request": { + "globals": { + "fetch": true + }, + "packages": { + "cross-fetch": true + } + }, + "gridplus-sdk": { + "globals": { + "console.error": true, + "setTimeout": true + }, + "packages": { + "aes-js": true, + "bech32": true, + "bignumber.js": true, + "bitwise": true, + "borc": true, + "bs58check": true, + "buffer": true, + "crc-32": true, + "elliptic": true, + "ethers": true, + "ethers-eip712": true, + "js-sha3": true, + "rlp-browser": true, + "secp256k1": true, + "superagent": true + } + }, + "hamt-sharding": { + "packages": { + "is-buffer": true, + "sparse-array": true + } + }, + "has-binary2": { + "globals": { + "Blob": true, + "File": true + }, + "packages": { + "buffer": true, + "isarray": true + } + }, + "has-cors": { + "globals": { + "XMLHttpRequest": true + } + }, + "hash-base": { + "packages": { + "inherits": true, + "safe-buffer": true, + "stream-browserify": true + } + }, + "hash.js": { + "packages": { + "inherits": true, + "minimalistic-assert": true + } + }, + "hdkey": { + "packages": { + "assert": true, + "coinstring": true, + "crypto-browserify": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "heap": { + "globals": { + "define": true + } + }, + "hi-base32": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "history": { + "globals": { + "addEventListener": true, + "confirm": true, + "document": true, + "history": true, + "location": true, + "navigator.userAgent": true, + "removeEventListener": true + }, + "packages": { + "resolve-pathname": true, + "tiny-invariant": true, + "tiny-warning": true, + "value-equal": true + } + }, + "hmac-drbg": { + "packages": { + "hash.js": true, + "minimalistic-assert": true, + "minimalistic-crypto-utils": true + } + }, + "hoist-non-react-statics": { + "packages": { + "react-is": true + } + }, + "https-browserify": { + "packages": { + "stream-http": true, + "url": true + } + }, + "https-did-resolver": { + "globals": { + "XMLHttpRequest": true + }, + "packages": { + "browser-resolve": true, + "did-resolver": true + } + }, + "human-to-milliseconds": { + "packages": { + "promisify-es6": true + } + }, + "idb-readable-stream": { + "globals": { + "IDBKeyRange.bound": true, + "IDBKeyRange.lowerBound": true, + "IDBKeyRange.upperBound": true + }, + "packages": { + "stream-browserify": true, + "xtend": true + } + }, + "idna-uts46": { + "globals": { + "define": true + }, + "packages": { + "punycode": true + } + }, + "idna-uts46-hx": { + "globals": { + "define": true + }, + "packages": { + "punycode": true + } + }, + "immediate": { + "globals": { + "MessageChannel": true, + "MutationObserver": true, + "WebKitMutationObserver": true, + "clearTimeout": true, + "document.createElement": true, + "document.createTextNode": true, + "document.documentElement.appendChild": true, + "setImmediate": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "interface-connection": { + "packages": { + "pull-defer": true + } + }, + "interface-datastore": { + "packages": { + "async": true, + "buffer": true, + "class-is": true, + "err-code": true, + "os-browserify": true, + "path-browserify": true, + "pull-defer": true, + "pull-stream": true, + "uuid": true + } + }, + "ip": { + "packages": { + "buffer": true, + "os-browserify": true + } + }, + "ipfs": { + "globals": { + "AbortController": true, + "clearInterval": true, + "clearTimeout": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "async": true, + "async-iterator-all": true, + "async-iterator-to-pull-stream": true, + "async-iterator-to-stream": true, + "base32.js": true, + "bignumber.js": true, + "browser-resolve": true, + "buffer": true, + "callbackify": true, + "cids": true, + "class-is": true, + "datastore-core": true, + "datastore-pubsub": true, + "debug": true, + "dlv": true, + "err-code": true, + "events": true, + "fnv1a": true, + "fsm-event": true, + "human-to-milliseconds": true, + "interface-datastore": true, + "ipfs-bitswap": true, + "ipfs-block": true, + "ipfs-block-service": true, + "ipfs-mfs": true, + "ipfs-repo": true, + "ipfs-unixfs": true, + "ipfs-unixfs-exporter": true, + "ipfs-unixfs-importer": true, + "ipfs-utils": true, + "ipld": true, + "ipld-dag-cbor": true, + "ipld-dag-pb": true, + "ipld-raw": true, + "ipns": true, + "is-buffer": true, + "is-ipfs": true, + "is-pull-stream": true, + "is-stream": true, + "iso-url": true, + "just-flatten-it": true, + "kind-of": true, + "libp2p": true, + "libp2p-bootstrap": true, + "libp2p-crypto": true, + "libp2p-kad-dht": true, + "libp2p-keychain": true, + "libp2p-record": true, + "libp2p-secio": true, + "libp2p-webrtc-star": true, + "libp2p-websocket-star-multi": true, + "libp2p-websockets": true, + "mafmt": true, + "merge-options": true, + "multiaddr": true, + "multiaddr-to-uri": true, + "multibase": true, + "multicodec": true, + "multihashes": true, + "multihashing-async": true, + "peer-book": true, + "peer-id": true, + "peer-info": true, + "promisify-es6": true, + "protons": true, + "pull-cat": true, + "pull-defer": true, + "pull-mplex": true, + "pull-pushable": true, + "pull-sort": true, + "pull-stream": true, + "pull-stream-to-async-iterator": true, + "pull-stream-to-stream": true, + "pull-traverse": true, + "readable-stream": true, + "receptacle": true, + "stream-to-pull-stream": true, + "superstruct": true, + "timers-browserify": true, + "varint": true + } + }, + "ipfs-bitswap": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "assert": true, + "async": true, + "bignumber.js": true, + "cids": true, + "debug": true, + "events": true, + "ipfs-block": true, + "just-debounce-it": true, + "lodash.isequalwith": true, + "moving-average": true, + "multicodec": true, + "multihashing-async": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true, + "varint-decoder": true + } + }, + "ipfs-block": { + "packages": { + "cids": true, + "class-is": true, + "is-buffer": true + } + }, + "ipfs-block-service": { + "packages": { + "async": true + } + }, + "ipfs-log": { + "globals": { + "clearTimeout": true, + "console.warn": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "json-stringify-deterministic": true, + "orbit-db-io": true, + "p-each-series": true, + "p-map": true, + "p-whilst": true + } + }, + "ipfs-mfs": { + "globals": { + "Blob": true, + "FileReader": true + }, + "packages": { + "assert": true, + "async-iterator-last": true, + "browser-resolve": true, + "buffer": true, + "cids": true, + "debug": true, + "err-code": true, + "hamt-sharding": true, + "interface-datastore": true, + "ipfs-unixfs": true, + "ipfs-unixfs-exporter": true, + "ipfs-unixfs-importer": true, + "ipld-dag-pb": true, + "mortice": true, + "multicodec": true, + "multihashes": true, + "promisify-es6": true + } + }, + "ipfs-mini": { + "globals": { + "XMLHttpRequest": true + } + }, + "ipfs-pubsub-1on1": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "events": true, + "path-browserify": true, + "safe-buffer": true + } + }, + "ipfs-pubsub-peer-monitor": { + "globals": { + "clearInterval": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "events": true + } + }, + "ipfs-repo": { + "packages": { + "assert": true, + "async": true, + "base32.js": true, + "bignumber.js": true, + "buffer": true, + "cids": true, + "datastore-core": true, + "datastore-level": true, + "debug": true, + "dlv": true, + "interface-datastore": true, + "ipfs-block": true, + "just-safe-set": true, + "path-browserify": true, + "pull-stream": true, + "sort-keys": true, + "timers-browserify": true + } + }, + "ipfs-unixfs": { + "packages": { + "protons": true + } + }, + "ipfs-unixfs-exporter": { + "packages": { + "async-iterator-last": true, + "buffer": true, + "cids": true, + "err-code": true, + "hamt-sharding": true, + "ipfs-unixfs": true, + "ipfs-unixfs-importer": true, + "is-buffer": true + } + }, + "ipfs-unixfs-importer": { + "packages": { + "async-iterator-all": true, + "async-iterator-batch": true, + "async-iterator-first": true, + "bl": true, + "buffer": true, + "deep-extend": true, + "err-code": true, + "hamt-sharding": true, + "ipfs-unixfs": true, + "ipld-dag-pb": true, + "multicodec": true, + "multihashes": true, + "multihashing-async": true, + "rabin-wasm": true, + "superstruct": true + } + }, + "ipfs-utils": { + "globals": { + "FileReader": true + }, + "packages": { + "is-buffer": true, + "is-pull-stream": true, + "is-stream": true, + "kind-of": true, + "readable-stream": true + } + }, + "ipld": { + "packages": { + "cids": true, + "ipfs-block": true, + "ipld-dag-cbor": true, + "ipld-dag-pb": true, + "ipld-raw": true, + "is-buffer": true, + "merge-options": true, + "multicodec": true, + "promisify-es6": true, + "typical": true + } + }, + "ipld-dag-cbor": { + "packages": { + "borc": true, + "buffer": true, + "cids": true, + "is-buffer": true, + "is-circular": true, + "multicodec": true, + "multihashing-async": true + } + }, + "ipld-dag-pb": { + "packages": { + "assert": true, + "buffer": true, + "cids": true, + "class-is": true, + "is-buffer": true, + "multicodec": true, + "multihashing-async": true, + "protons": true, + "stable": true + } + }, + "ipld-raw": { + "packages": { + "cids": true, + "multicodec": true, + "multihashing-async": true + } + }, + "ipns": { + "packages": { + "base32-encode": true, + "buffer": true, + "debug": true, + "interface-datastore": true, + "libp2p-crypto": true, + "multihashes": true, + "peer-id": true, + "protons": true, + "timestamp-nano": true + } + }, + "is-dom": { + "globals": { + "Node": true + }, + "packages": { + "is-object": true, + "is-window": true + } + }, + "is-in-browser": { + "globals": { + "document": true + } + }, + "is-ip": { + "packages": { + "ip-regex": true + } + }, + "is-ipfs": { + "packages": { + "bs58": true, + "buffer": true, + "cids": true, + "mafmt": true, + "multiaddr": true, + "multibase": true, + "multihashes": true + } + }, + "is-regex": { + "packages": { + "has-symbols": true + } + }, + "iso-random-stream": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "buffer": true + } + }, + "iso-url": { + "globals": { + "URL": true, + "URLSearchParams": true, + "location": true + } + }, + "isomorphic-fetch": { + "globals": { + "fetch.bind": true + }, + "packages": { + "whatwg-fetch": true + } + }, + "js-base64": { + "globals": { + "Base64": "write", + "TextDecoder": true, + "TextEncoder": true, + "atob": true, + "btoa": true, + "define": true + }, + "packages": { + "buffer": true + } + }, + "js-sha256": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "js-sha3": { + "globals": { + "define": true + }, + "packages": { + "process": true + } + }, + "jsan": { + "globals": { + "console.warn": true + } + }, + "json-rpc-engine": { + "packages": { + "@metamask/safe-event-emitter": true, + "eth-rpc-errors": true, + "safe-event-emitter": true + } + }, + "json-rpc-middleware-stream": { + "packages": { + "readable-stream": true + } + }, + "json-stable-stringify": { + "packages": { + "jsonify": true + } + }, + "jsonschema": { + "packages": { + "url": true + } + }, + "jss": { + "globals": { + "CSS": true, + "document.createElement": true, + "document.querySelector": true + }, + "packages": { + "@babel/runtime": true, + "is-in-browser": true, + "tiny-warning": true + } + }, + "jss-plugin-camel-case": { + "packages": { + "hyphenate-style-name": true + } + }, + "jss-plugin-default-unit": { + "globals": { + "CSS": true + }, + "packages": { + "jss": true + } + }, + "jss-plugin-global": { + "packages": { + "@babel/runtime": true, + "jss": true + } + }, + "jss-plugin-nested": { + "packages": { + "@babel/runtime": true, + "tiny-warning": true + } + }, + "jss-plugin-rule-value-function": { + "packages": { + "jss": true, + "tiny-warning": true + } + }, + "jss-plugin-vendor-prefixer": { + "packages": { + "css-vendor": true, + "jss": true + } + }, + "just-debounce-it": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "k-bucket": { + "packages": { + "events": true, + "randombytes": true + } + }, + "keccak": { + "packages": { + "buffer": true, + "inherits": true, + "safe-buffer": true, + "stream-browserify": true + } + }, + "latency-monitor": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "document": true, + "performance": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "debug": true, + "events": true, + "lodash": true, + "process": true + } + }, + "level-codec": { + "packages": { + "buffer": true + } + }, + "level-errors": { + "packages": { + "errno": true + } + }, + "level-iterator-stream": { + "packages": { + "inherits": true, + "readable-stream": true, + "xtend": true + } + }, + "level-js": { + "globals": { + "IDBKeyRange.bound": true, + "IDBKeyRange.lowerBound": true, + "IDBKeyRange.only": true, + "IDBKeyRange.upperBound": true, + "indexedDB": true + }, + "packages": { + "abstract-leveldown": true, + "buffer": true, + "idb-readable-stream": true, + "immediate": true, + "inherits": true, + "is-buffer": true, + "ltgt": true, + "process": true, + "stream-browserify": true, + "typedarray-to-buffer": true, + "util": true, + "xtend": true + } + }, + "levelup": { + "packages": { + "assert": true, + "deferred-leveldown": true, + "events": true, + "level-errors": true, + "level-iterator-stream": true, + "process": true, + "util": true, + "xtend": true + } + }, + "libp2p": { + "packages": { + "async": true, + "debug": true, + "err-code": true, + "events": true, + "fsm-event": true, + "is-buffer": true, + "libp2p-connection-manager": true, + "libp2p-floodsub": true, + "libp2p-ping": true, + "libp2p-switch": true, + "libp2p-websockets": true, + "multiaddr": true, + "once": true, + "peer-book": true, + "peer-id": true, + "peer-info": true, + "process": true, + "superstruct": true + } + }, + "libp2p-bootstrap": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "async": true, + "debug": true, + "events": true, + "mafmt": true, + "multiaddr": true, + "peer-id": true, + "peer-info": true + } + }, + "libp2p-circuit": { + "packages": { + "async": true, + "debug": true, + "events": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-connection-manager": { + "packages": { + "debug": true, + "events": true, + "latency-monitor": true + } + }, + "libp2p-crypto": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "asn1.js": true, + "async": true, + "browserify-aes": true, + "bs58": true, + "buffer": true, + "iso-random-stream": true, + "libp2p-crypto-secp256k1": true, + "multihashing-async": true, + "node-forge": true, + "protons": true, + "tweetnacl": true + } + }, + "libp2p-crypto-secp256k1": { + "packages": { + "async": true, + "bs58": true, + "multihashing-async": true, + "secp256k1": true + } + }, + "libp2p-floodsub": { + "packages": { + "assert": true, + "async": true, + "debug": true, + "libp2p-pubsub": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-identify": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "multiaddr": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-kad-dht": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "abort-controller": true, + "assert": true, + "async": true, + "base32.js": true, + "buffer": true, + "cids": true, + "debug": true, + "err-code": true, + "events": true, + "hashlru": true, + "heap": true, + "interface-datastore": true, + "is-buffer": true, + "k-bucket": true, + "libp2p-crypto": true, + "libp2p-record": true, + "multihashes": true, + "multihashing-async": true, + "p-queue": true, + "p-times": true, + "peer-id": true, + "peer-info": true, + "promise-to-callback": true, + "promisify-es6": true, + "protons": true, + "pull-length-prefixed": true, + "pull-stream": true, + "pull-stream-to-async-iterator": true, + "varint": true, + "xor-distance": true + } + }, + "libp2p-keychain": { + "globals": { + "setTimeout": true + }, + "packages": { + "async": true, + "buffer": true, + "err-code": true, + "interface-datastore": true, + "libp2p-crypto": true, + "merge-options": true, + "node-forge": true, + "pull-stream": true, + "sanitize-filename": true + } + }, + "libp2p-ping": { + "packages": { + "debug": true, + "events": true, + "libp2p-crypto": true, + "pull-handshake": true, + "pull-stream": true + } + }, + "libp2p-pubsub": { + "packages": { + "async": true, + "bs58": true, + "buffer": true, + "debug": true, + "err-code": true, + "events": true, + "is-buffer": true, + "libp2p-crypto": true, + "protons": true, + "pull-length-prefixed": true, + "pull-pushable": true, + "pull-stream": true, + "time-cache": true + } + }, + "libp2p-record": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "buffer-split": true, + "err-code": true, + "is-buffer": true, + "multihashing-async": true, + "protons": true + } + }, + "libp2p-secio": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "debug": true, + "interface-connection": true, + "libp2p-crypto": true, + "multihashing-async": true, + "once": true, + "peer-id": true, + "peer-info": true, + "protons": true, + "pull-defer": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true + } + }, + "libp2p-switch": { + "packages": { + "assert": true, + "async": true, + "bignumber.js": true, + "class-is": true, + "debug": true, + "err-code": true, + "events": true, + "fsm-event": true, + "hashlru": true, + "interface-connection": true, + "libp2p-circuit": true, + "libp2p-identify": true, + "moving-average": true, + "multiaddr": true, + "multistream-select": true, + "once": true, + "peer-id": true, + "peer-info": true, + "pull-stream": true, + "retimer": true + } + }, + "libp2p-webrtc-star": { + "packages": { + "async": true, + "class-is": true, + "debug": true, + "events": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "simple-peer": true, + "socket.io-client": true, + "stream-to-pull-stream": true, + "webrtcsupport": true + } + }, + "libp2p-websocket-star": { + "globals": { + "console.error": true + }, + "packages": { + "async": true, + "buffer": true, + "class-is": true, + "debug": true, + "events": true, + "interface-connection": true, + "libp2p-crypto": true, + "mafmt": true, + "multiaddr": true, + "once": true, + "peer-id": true, + "peer-info": true, + "pull-stream": true, + "socket.io-client": true, + "socket.io-pull-stream": true, + "uuid": true + } + }, + "libp2p-websocket-star-multi": { + "globals": { + "setTimeout": true + }, + "packages": { + "async": true, + "debug": true, + "events": true, + "libp2p-websocket-star": true, + "mafmt": true, + "multiaddr": true, + "once": true + } + }, + "libp2p-websockets": { + "packages": { + "class-is": true, + "debug": true, + "interface-connection": true, + "mafmt": true, + "multiaddr": true, + "multiaddr-to-uri": true, + "os-browserify": true, + "pull-ws": true + } + }, + "locale-currency": { + "globals": { + "countryCode": true + } + }, + "localforage": { + "globals": { + "Blob": true, + "BlobBuilder": true, + "FileReader": true, + "IDBKeyRange": true, + "MSBlobBuilder": true, + "MozBlobBuilder": true, + "OIndexedDB": true, + "WebKitBlobBuilder": true, + "atob": true, + "btoa": true, + "console.error": true, + "console.info": true, + "console.warn": true, + "define": true, + "fetch": true, + "indexedDB": true, + "localStorage": true, + "mozIndexedDB": true, + "msIndexedDB": true, + "navigator.platform": true, + "navigator.userAgent": true, + "openDatabase": true, + "setTimeout": true, + "webkitIndexedDB": true + } + }, + "lodash": { + "globals": { + "define": true + } + }, + "lodash.throttle": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "loglevel": { + "globals": { + "console": true, + "define": true, + "document.cookie": true, + "localStorage": true, + "log": "write" + } + }, + "logplease": { + "globals": { + "LOG": true, + "console.error": true, + "console.log": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "process": true, + "util": true + } + }, + "lru": { + "packages": { + "events": true, + "inherits": true + } + }, + "ltgt": { + "packages": { + "is-buffer": true + } + }, + "luxon": { + "globals": { + "Intl": true + } + }, + "mafmt": { + "packages": { + "multiaddr": true + } + }, + "md5": { + "packages": { + "charenc": true, + "crypt": true, + "is-buffer": true + } + }, + "md5.js": { + "packages": { + "hash-base": true, + "inherits": true, + "safe-buffer": true + } + }, + "merge-options": { + "packages": { + "is-plain-obj": true + } + }, + "miller-rabin": { + "packages": { + "bn.js": true, + "brorand": true + } + }, + "mini-create-react-context": { + "packages": { + "@babel/runtime": true, + "gud": true, + "prop-types": true, + "react": true, + "tiny-warning": true + } + }, + "mortice": { + "globals": { + "Worker": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "observable-webworkers": true, + "p-queue": true, + "process": true, + "promise-timeout": true, + "shortid": true + } + }, + "multiaddr": { + "packages": { + "bs58": true, + "buffer": true, + "class-is": true, + "hi-base32": true, + "ip": true, + "is-ip": true, + "varint": true + } + }, + "multiaddr-to-uri": { + "packages": { + "multiaddr": true + } + }, + "multibase": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@multiformats/base-x": true, + "base-x": true, + "buffer": true, + "web-encoding": true + } + }, + "multicodec": { + "packages": { + "buffer": true, + "uint8arrays": true, + "varint": true + } + }, + "multihashes": { + "packages": { + "bs58": true, + "buffer": true, + "multibase": true, + "uint8arrays": true, + "varint": true, + "web-encoding": true + } + }, + "multihashing-async": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "blakejs": true, + "buffer": true, + "err-code": true, + "js-sha3": true, + "multihashes": true, + "murmurhash3js": true, + "murmurhash3js-revisited": true, + "nodeify": true, + "process": true + } + }, + "multistream-select": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "debug": true, + "err-code": true, + "interface-connection": true, + "once": true, + "pull-handshake": true, + "pull-length-prefixed": true, + "pull-stream": true, + "semver": true, + "varint": true + } + }, + "muport-did-resolver": { + "packages": { + "@babel/runtime": true, + "did-resolver": true, + "node-fetch": true + } + }, + "murmurhash3js": { + "globals": { + "define": true + } + }, + "murmurhash3js-revisited": { + "globals": { + "define": true + } + }, + "nanoid": { + "globals": { + "crypto": true, + "msCrypto": true, + "navigator": true + }, + "packages": { + "buffer": true, + "crypto-browserify": true + } + }, + "node-forge": { + "globals": { + "Blob": true, + "MutationObserver": true, + "QuotaExceededError": true, + "URL.createObjectURL": true, + "URL.revokeObjectURL": true, + "Worker": true, + "addEventListener": true, + "document": true, + "jQuery": true, + "localStorage": true, + "location": true, + "navigator": true, + "postMessage": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "browser-resolve": true, + "process": true, + "timers-browserify": true + } + }, + "nodeify": { + "globals": { + "setTimeout": true + }, + "packages": { + "is-promise": true, + "process": true, + "promise": true, + "timers-browserify": true + } + }, + "nonce-tracker": { + "packages": { + "assert": true, + "await-semaphore": true, + "ethjs-query": true + } + }, + "number-to-bn": { + "packages": { + "bn.js": true, + "strip-hex-prefix": true + } + }, + "obj-multiplex": { + "globals": { + "console.warn": true + }, + "packages": { + "end-of-stream": true, + "once": true, + "readable-stream": true + } + }, + "obs-store": { + "packages": { + "safe-event-emitter": true, + "xtend": true + } + }, + "once": { + "packages": { + "wrappy": true + } + }, + "orbit-db": { + "globals": { + "console.log": true + }, + "packages": { + "cids": true, + "ipfs-pubsub-1on1": true, + "logplease": true, + "multihashes": true, + "orbit-db-access-controllers": true, + "orbit-db-cache": true, + "orbit-db-counterstore": true, + "orbit-db-docstore": true, + "orbit-db-eventstore": true, + "orbit-db-feedstore": true, + "orbit-db-identity-provider": true, + "orbit-db-io": true, + "orbit-db-keystore": true, + "orbit-db-kvstore": true, + "orbit-db-pubsub": true, + "path-browserify": true + } + }, + "orbit-db-access-controllers": { + "globals": { + "console.log": true + }, + "packages": { + "events": true, + "orbit-db-io": true, + "p-map-series": true, + "path-browserify": true, + "safe-buffer": true + } + }, + "orbit-db-cache": { + "packages": { + "level-js": true, + "logplease": true, + "path-browserify": true + } + }, + "orbit-db-counterstore": { + "packages": { + "crdts": true, + "orbit-db-store": true + } + }, + "orbit-db-docstore": { + "packages": { + "orbit-db-store": true, + "p-map": true, + "readable-stream": true + } + }, + "orbit-db-eventstore": { + "packages": { + "orbit-db-store": true + } + }, + "orbit-db-feedstore": { + "packages": { + "orbit-db-eventstore": true + } + }, + "orbit-db-identity-provider": { + "packages": { + "orbit-db-keystore": true + } + }, + "orbit-db-io": { + "packages": { + "buffer": true, + "cids": true, + "ipld-dag-pb": true + } + }, + "orbit-db-keystore": { + "globals": { + "console.error": true, + "console.log": true + }, + "packages": { + "elliptic": true, + "level-js": true, + "levelup": true, + "libp2p-crypto": true, + "lru": true, + "safe-buffer": true, + "secp256k1": true + } + }, + "orbit-db-kvstore": { + "packages": { + "orbit-db-store": true + } + }, + "orbit-db-pubsub": { + "packages": { + "buffer": true, + "ipfs-pubsub-peer-monitor": true, + "logplease": true, + "p-series": true + } + }, + "orbit-db-store": { + "globals": { + "clearInterval": true, + "console.error": true, + "console.warn": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "events": true, + "ipfs-log": true, + "logplease": true, + "orbit-db-io": true, + "p-each-series": true, + "p-map": true, + "readable-stream": true + } + }, + "os-browserify": { + "globals": { + "location": true, + "navigator": true + } + }, + "p-each-series": { + "packages": { + "p-reduce": true + } + }, + "p-map-series": { + "packages": { + "p-reduce": true + } + }, + "p-queue": { + "globals": { + "clearInterval": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "eventemitter3": true + } + }, + "p-series": { + "packages": { + "@sindresorhus/is": true, + "p-reduce": true + } + }, + "p-times": { + "packages": { + "p-map": true + } + }, + "parse-asn1": { + "packages": { + "asn1.js": true, + "browserify-aes": true, + "buffer": true, + "evp_bytestokey": true, + "pbkdf2": true + } + }, + "path-browserify": { + "packages": { + "process": true + } + }, + "path-to-regexp": { + "packages": { + "isarray": true + } + }, + "pbkdf2": { + "globals": { + "crypto": true, + "process": true + }, + "packages": { + "create-hash": true, + "process": true, + "ripemd160": true, + "safe-buffer": true, + "sha.js": true + } + }, + "peer-book": { + "packages": { + "bs58": true, + "is-buffer": true, + "peer-id": true, + "peer-info": true + } + }, + "peer-id": { + "packages": { + "assert": true, + "async": true, + "buffer": true, + "class-is": true, + "libp2p-crypto": true, + "multihashes": true + } + }, + "peer-info": { + "packages": { + "assert": true, + "multiaddr": true, + "peer-id": true, + "unique-by": true + } + }, + "popper.js": { + "globals": { + "MSInputMethodContext": true, + "Node.DOCUMENT_POSITION_FOLLOWING": true, + "cancelAnimationFrame": true, + "console.warn": true, + "define": true, + "devicePixelRatio": true, + "document": true, + "getComputedStyle": true, + "innerHeight": true, + "innerWidth": true, + "navigator": true, + "requestAnimationFrame": true, + "setTimeout": true + } + }, + "precond": { + "packages": { + "util": true + } + }, + "process": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "process-nextick-args": { + "packages": { + "process": true + } + }, + "promise": { + "globals": { + "setImediate": true, + "setTimeout": true + }, + "packages": { + "is-promise": true, + "process": true + } + }, + "promise-timeout": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "promise-to-callback": { + "packages": { + "is-fn": true, + "set-immediate-shim": true + } + }, + "prop-types": { + "globals": { + "console": true + }, + "packages": { + "object-assign": true, + "react-is": true + } + }, + "protons": { + "packages": { + "buffer": true, + "is-buffer": true, + "protocol-buffers-schema": true, + "safe-buffer": true, + "signed-varint": true, + "varint": true + } + }, + "public-encrypt": { + "packages": { + "bn.js": true, + "browserify-rsa": true, + "buffer": true, + "create-hash": true, + "parse-asn1": true, + "randombytes": true + } + }, + "pubnub": { + "globals": { + "ActiveXObject": true, + "XMLHttpRequest": true, + "addEventListener": true, + "btoa": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "define": true, + "localStorage.getItem": true, + "localStorage.setItem": true, + "location": true, + "navigator": true, + "setInterval": true, + "setTimeout": true + } + }, + "pull-handshake": { + "packages": { + "pull-cat": true, + "pull-pair": true, + "pull-pushable": true, + "pull-reader": true + } + }, + "pull-length-prefixed": { + "packages": { + "pull-pushable": true, + "pull-reader": true, + "safe-buffer": true, + "varint": true + } + }, + "pull-mplex": { + "packages": { + "async": true, + "buffer": true, + "debug": true, + "events": true, + "interface-connection": true, + "looper": true, + "pull-abortable": true, + "pull-pushable": true, + "pull-stream": true, + "pull-through": true, + "varint": true + } + }, + "pull-reader": { + "globals": { + "cb": true, + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "buffer": true + } + }, + "pull-sort": { + "packages": { + "pull-defer": true, + "pull-stream": true + } + }, + "pull-stream": { + "globals": { + "console.log": true + } + }, + "pull-stream-to-async-iterator": { + "packages": { + "pull-stream": true + } + }, + "pull-stream-to-stream": { + "packages": { + "process": true, + "stream-browserify": true, + "timers-browserify": true + } + }, + "pull-through": { + "packages": { + "looper": true + } + }, + "pull-ws": { + "globals": { + "WebSocket": true, + "location": true + }, + "packages": { + "browser-resolve": true, + "events": true, + "https-browserify": true, + "process": true, + "relative-url": true, + "safe-buffer": true, + "stream-http": true, + "timers-browserify": true, + "url": true + } + }, + "pump": { + "packages": { + "browser-resolve": true, + "end-of-stream": true, + "once": true, + "process": true + } + }, + "punycode": { + "globals": { + "define": true + } + }, + "qrcode-generator": { + "globals": { + "define": true + } + }, + "rabin-wasm": { + "globals": { + "Blob": true, + "Response": true, + "WebAssembly": true + }, + "packages": { + "assemblyscript": true + } + }, + "randombytes": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "process": true, + "safe-buffer": true + } + }, + "randomfill": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "process": true, + "randombytes": true, + "safe-buffer": true + } + }, + "react": { + "globals": { + "console": true + }, + "packages": { + "object-assign": true, + "prop-types": true + } + }, + "react-dnd": { + "globals": { + "console.error": true + }, + "packages": { + "disposables": true, + "dnd-core": true, + "hoist-non-react-statics": true, + "invariant": true, + "lodash": true, + "prop-types": true, + "react": true, + "shallowequal": true + } + }, + "react-dnd-html5-backend": { + "globals": { + "Image": true, + "console.warn": true, + "devicePixelRatio": true, + "document": true, + "navigator.userAgent": true, + "safari": true, + "setTimeout": true + } + }, + "react-dom": { + "globals": { + "MSApp": true, + "__REACT_DEVTOOLS_GLOBAL_HOOK__": true, + "addEventListener": true, + "clearTimeout": true, + "clipboardData": true, + "console": true, + "dispatchEvent": true, + "document": true, + "event": "write", + "jest": true, + "location.protocol": true, + "navigator.userAgent.indexOf": true, + "performance": true, + "removeEventListener": true, + "self": true, + "setTimeout": true, + "top": true, + "trustedTypes": true + }, + "packages": { + "object-assign": true, + "prop-types": true, + "react": true, + "scheduler": true + } + }, + "react-easy-swipe": { + "globals": { + "addEventListener": true, + "define": true, + "document.addEventListener": true, + "document.removeEventListener": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-fast-compare": { + "globals": { + "Element": true, + "console.warn": true + } + }, + "react-idle-timer": { + "globals": { + "clearTimeout": true, + "document": true, + "setTimeout": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-inspector": { + "globals": { + "Node.CDATA_SECTION_NODE": true, + "Node.COMMENT_NODE": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_TYPE_NODE": true, + "Node.ELEMENT_NODE": true, + "Node.PROCESSING_INSTRUCTION_NODE": true, + "Node.TEXT_NODE": true + }, + "packages": { + "babel-runtime": true, + "is-dom": true, + "prop-types": true, + "react": true + } + }, + "react-is": { + "globals": { + "console": true + } + }, + "react-popper": { + "globals": { + "document": true + }, + "packages": { + "@popperjs/core": true, + "react": true, + "react-fast-compare": true, + "warning": true + } + }, + "react-redux": { + "globals": { + "console": true, + "document": true + }, + "packages": { + "@babel/runtime": true, + "hoist-non-react-statics": true, + "prop-types": true, + "react": true, + "react-dom": true, + "react-is": true, + "redux": true + } + }, + "react-responsive-carousel": { + "globals": { + "HTMLElement": true, + "clearTimeout": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "setTimeout": true + }, + "packages": { + "classnames": true, + "react": true, + "react-dom": true, + "react-easy-swipe": true + } + }, + "react-router": { + "packages": { + "history": true, + "hoist-non-react-statics": true, + "mini-create-react-context": true, + "path-to-regexp": true, + "prop-types": true, + "react": true, + "react-is": true, + "tiny-invariant": true, + "tiny-warning": true + } + }, + "react-router-dom": { + "packages": { + "history": true, + "prop-types": true, + "react": true, + "react-router": true, + "tiny-invariant": true, + "tiny-warning": true + } + }, + "react-simple-file-input": { + "globals": { + "File": true, + "FileReader": true, + "console.warn": true + }, + "packages": { + "prop-types": true, + "react": true + } + }, + "react-tippy": { + "globals": { + "Element": true, + "MSStream": true, + "MutationObserver": true, + "addEventListener": true, + "clearTimeout": true, + "console.error": true, + "console.warn": true, + "define": true, + "document": true, + "getComputedStyle": true, + "innerHeight": true, + "innerWidth": true, + "navigator.maxTouchPoints": true, + "navigator.msMaxTouchPoints": true, + "navigator.userAgent": true, + "performance": true, + "requestAnimationFrame": true, + "setTimeout": true + }, + "packages": { + "popper.js": true, + "react": true, + "react-dom": true + } + }, + "react-toggle-button": { + "globals": { + "clearTimeout": true, + "console.warn": true, + "define": true, + "performance": true, + "setTimeout": true + }, + "packages": { + "react": true + } + }, + "react-transition-group": { + "globals": { + "Element": true, + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "chain-function": true, + "dom-helpers": true, + "prop-types": true, + "react": true, + "react-dom": true, + "warning": true + } + }, + "readable-stream": { + "packages": { + "browser-resolve": true, + "buffer": true, + "core-util-is": true, + "events": true, + "inherits": true, + "isarray": true, + "process": true, + "process-nextick-args": true, + "safe-buffer": true, + "string_decoder": true, + "timers-browserify": true, + "util-deprecate": true + } + }, + "receptacle": { + "globals": { + "clearTimeout": true, + "setTimeout": true + }, + "packages": { + "ms": true + } + }, + "redux": { + "globals": { + "console": true + }, + "packages": { + "@babel/runtime": true, + "symbol-observable": true + } + }, + "redux-devtools-core": { + "globals": { + "ErrorUtils": true, + "console": true, + "devToolsOptions": true, + "onerror": "write", + "serializeState": true + }, + "packages": { + "get-params": true, + "jsan": true, + "lodash": true, + "nanoid": true, + "remotedev-serialize": true + } + }, + "redux-devtools-instrument": { + "globals": { + "chrome": true, + "console.error": true, + "process": true, + "setTimeout": true + }, + "packages": { + "lodash": true, + "process": true, + "symbol-observable": true + } + }, + "regenerator-runtime": { + "globals": { + "regeneratorRuntime": "write" + } + }, + "regexp.prototype.flags": { + "packages": { + "define-properties": true, + "es-abstract": true + } + }, + "relative-url": { + "packages": { + "url": true + } + }, + "remote-redux-devtools": { + "globals": { + "console.log": true, + "console.warn": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "jsan": true, + "redux-devtools-core": true, + "redux-devtools-instrument": true, + "rn-host-detect": true, + "socketcluster-client": true + } + }, + "retimer": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "ripemd160": { + "packages": { + "buffer": true, + "hash-base": true, + "inherits": true + } + }, + "rlp": { + "packages": { + "bn.js": true, + "buffer": true + } + }, + "rlp-browser": { + "packages": { + "assert": true, + "buffer": true + } + }, + "rn-host-detect": { + "globals": { + "__DEV__": true, + "__fbBatchedBridgeConfig": true, + "console": true + } + }, + "rpc-cap": { + "packages": { + "@metamask/controllers": true, + "eth-rpc-errors": true, + "is-subset": true, + "json-rpc-engine": true, + "uuid": true + } + }, + "safe-buffer": { + "packages": { + "buffer": true + } + }, + "safe-event-emitter": { + "globals": { + "setTimeout": true + }, + "packages": { + "events": true, + "util": true + } + }, + "sanitize-filename": { + "packages": { + "truncate-utf8-bytes": true + } + }, + "sc-channel": { + "packages": { + "component-emitter": true + } + }, + "sc-formatter": { + "globals": { + "Buffer": true + } + }, + "scheduler": { + "globals": { + "MessageChannel": true, + "cancelAnimationFrame": true, + "clearTimeout": true, + "console": true, + "navigator": true, + "performance": true, + "requestAnimationFrame": true, + "setTimeout": true + } + }, + "scrypt-js": { + "globals": { + "define": true, + "setTimeout": true + }, + "packages": { + "timers-browserify": true + } + }, + "scryptsy": { + "packages": { + "buffer": true, + "pbkdf2": true + } + }, + "secp256k1": { + "packages": { + "bip66": true, + "bn.js": true, + "create-hash": true, + "drbg.js": true, + "elliptic": true, + "is-buffer": true, + "safe-buffer": true + } + }, + "semaphore": { + "globals": { + "define": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "semver": { + "globals": { + "console": true + }, + "packages": { + "process": true + } + }, + "set-immediate-shim": { + "globals": { + "setTimeout.apply": true + }, + "packages": { + "timers-browserify": true + } + }, + "sha.js": { + "packages": { + "inherits": true, + "safe-buffer": true + } + }, + "shortid": { + "globals": { + "crypto": true, + "msCrypto": true + }, + "packages": { + "nanoid": true + } + }, + "signed-varint": { + "packages": { + "varint": true + } + }, + "simple-peer": { + "globals": { + "clearInterval": true, + "console.warn": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "debug": true, + "get-browser-rtc": true, + "inherits": true, + "randombytes": true, + "readable-stream": true + } + }, + "socket.io-client": { + "globals": { + "clearTimeout": true, + "location": true, + "setTimeout": true + }, + "packages": { + "backo2": true, + "component-bind": true, + "component-emitter": true, + "debug": true, + "engine.io-client": true, + "has-binary2": true, + "indexof": true, + "parseqs": true, + "parseuri": true, + "socket.io-parser": true, + "to-array": true + } + }, + "socket.io-parser": { + "globals": { + "Blob": true, + "File": true, + "FileReader": true + }, + "packages": { + "buffer": true, + "component-emitter": true, + "debug": true, + "isarray": true + } + }, + "socket.io-pull-stream": { + "globals": { + "console.error": true + }, + "packages": { + "buffer": true, + "data-queue": true, + "debug": true, + "pull-stream": true, + "uuid": true + } + }, + "socketcluster-client": { + "globals": { + "WebSocket": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "clearTimeout": true, + "localStorage": true, + "location": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "clone": true, + "component-emitter": true, + "linked-list": true, + "querystring-es3": true, + "sc-channel": true, + "sc-errors": true, + "sc-formatter": true, + "uuid": true + } + }, + "sort-keys": { + "packages": { + "is-plain-obj": true + } + }, + "stable": { + "globals": { + "define": true + } + }, + "store": { + "globals": { + "ActiveXObject": true, + "console": true + } + }, + "stream-browserify": { + "packages": { + "events": true, + "inherits": true, + "readable-stream": true + } + }, + "stream-http": { + "globals": { + "AbortController": true, + "Blob": true, + "MSStreamReader": true, + "ReadableStream": true, + "WritableStream": true, + "XDomainRequest": true, + "XMLHttpRequest": true, + "clearTimeout": true, + "fetch": true, + "location.protocol.search": true, + "setTimeout": true + }, + "packages": { + "buffer": true, + "builtin-status-codes": true, + "inherits": true, + "process": true, + "readable-stream": true, + "url": true, + "xtend": true + } + }, + "stream-to-pull-stream": { + "globals": { + "console.error": true + }, + "packages": { + "looper": true, + "process": true, + "pull-stream": true + } + }, + "string_decoder": { + "packages": { + "safe-buffer": true + } + }, + "strip-hex-prefix": { + "packages": { + "is-hex-prefixed": true + } + }, + "superagent": { + "globals": { + "ActiveXObject": true, + "XMLHttpRequest": true, + "btoa": true, + "clearTimeout": true, + "console.error": true, + "console.trace": true, + "console.warn": true, + "setTimeout": true + }, + "packages": { + "component-emitter": true + } + }, + "textarea-caret": { + "globals": { + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true, + "document.querySelector": true, + "getCaretCoordinates": "write", + "getComputedStyle": true, + "mozInnerScreenX": true + } + }, + "through": { + "packages": { + "process": true, + "stream-browserify": true + } + }, + "through2": { + "packages": { + "process": true, + "readable-stream": true, + "util": true, + "xtend": true + } + }, + "time-cache": { + "packages": { + "lodash.throttle": true + } + }, + "timers-browserify": { + "globals": { + "clearInterval": true, + "clearTimeout": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "process": true + } + }, + "tiny-warning": { + "globals": { + "console": true + } + }, + "toggle-selection": { + "globals": { + "document.activeElement": true, + "document.getSelection": true + } + }, + "trezor-connect": { + "globals": { + "__TREZOR_CONNECT_SRC": true, + "addEventListener": true, + "btoa": true, + "chrome": true, + "clearInterval": true, + "clearTimeout": true, + "console": true, + "document.body": true, + "document.createElement": true, + "document.createTextNode": true, + "document.getElementById": true, + "document.querySelectorAll": true, + "fetch": true, + "location": true, + "navigator": true, + "open": true, + "removeEventListener": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "events": true, + "whatwg-fetch": true + } + }, + "truncate-utf8-bytes": { + "packages": { + "utf8-byte-length": true + } + }, + "tslib": { + "globals": { + "define": true + } + }, + "tweetnacl": { + "globals": { + "crypto": true, + "msCrypto": true, + "nacl": "write" + }, + "packages": { + "browser-resolve": true + } + }, + "tweetnacl-util": { + "globals": { + "atob": true, + "btoa": true + }, + "packages": { + "browser-resolve": true + } + }, + "typedarray-to-buffer": { + "packages": { + "buffer": true, + "is-typedarray": true + } + }, + "typical": { + "globals": { + "define": true + } + }, + "uint8arrays": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "multibase": true, + "web-encoding": true + } + }, + "unorm": { + "globals": { + "define": true + } + }, + "uport-base64url": { + "packages": { + "buffer": true + } + }, + "url": { + "packages": { + "punycode": true, + "querystring-es3": true + } + }, + "utf8": { + "globals": { + "define": true + } + }, + "util": { + "globals": { + "console.error": true, + "console.log": true, + "console.trace": true, + "process": true + }, + "packages": { + "inherits": true, + "process": true + } + }, + "util-deprecate": { + "globals": { + "console.trace": true, + "console.warn": true, + "localStorage": true + } + }, + "uuid": { + "globals": { + "crypto": true, + "msCrypto": true + } + }, + "varint-decoder": { + "packages": { + "is-buffer": true, + "varint": true + } + }, + "vm-browserify": { + "globals": { + "document.body.appendChild": true, + "document.body.removeChild": true, + "document.createElement": true + } + }, + "warning": { + "globals": { + "console": true + } + }, + "web-encoding": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "util": true + } + }, + "web3": { + "globals": { + "Web3": "write", + "XMLHttpRequest": "write", + "clearTimeout": true, + "console.error": true, + "setTimeout": true + }, + "packages": { + "bignumber.js": true, + "buffer": true, + "crypto-js": true, + "utf8": true, + "xhr2-cookies": true + } + }, + "web3-provider-engine": { + "globals": { + "WebSocket": true, + "console": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/tx": true, + "async": true, + "backoff": true, + "browser-resolve": true, + "buffer": true, + "eth-block-tracker": true, + "eth-json-rpc-filters": true, + "eth-json-rpc-infura": true, + "eth-json-rpc-middleware": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "events": true, + "json-stable-stringify": true, + "semaphore": true, + "util": true, + "xtend": true + } + }, + "web3-stream-provider": { + "globals": { + "setTimeout": true + }, + "packages": { + "readable-stream": true, + "util": true, + "uuid": true + } + }, + "webrtcsupport": { + "globals": { + "AudioContext": true, + "MediaStream": true, + "RTCIceCandidate": true, + "RTCPeerConnection": true, + "RTCSessionDescription": true, + "document": true, + "location.protocol": true, + "mozRTCIceCandidate": true, + "mozRTCPeerConnection": true, + "mozRTCSessionDescription": true, + "navigator.getUserMedia": true, + "navigator.mozGetUserMedia": true, + "navigator.msGetUserMedia": true, + "navigator.userAgent.match": true, + "navigator.webkitGetUserMedia": true, + "webkitAudioContext": true, + "webkitMediaStream": true, + "webkitRTCPeerConnection": true + } + }, + "whatwg-fetch": { + "globals": { + "Blob": true, + "FileReader": true, + "FormData": true, + "URLSearchParams.prototype.isPrototypeOf": true, + "XMLHttpRequest": true, + "define": true, + "setTimeout": true + } + }, + "xhr2": { + "globals": { + "XMLHttpRequest": true + } + }, + "xhr2-cookies": { + "globals": { + "console.warn": true + }, + "packages": { + "buffer": true, + "cookiejar": true, + "https-browserify": true, + "os-browserify": true, + "process": true, + "stream-http": true, + "url": true + } + }, + "xor-distance": { + "packages": { + "buffer": true + } + } + } +} \ No newline at end of file diff --git a/lavamoat/node/policy-override.json b/lavamoat/build-system/policy-override.json similarity index 100% rename from lavamoat/node/policy-override.json rename to lavamoat/build-system/policy-override.json diff --git a/lavamoat/node/policy.json b/lavamoat/build-system/policy.json similarity index 100% rename from lavamoat/node/policy.json rename to lavamoat/build-system/policy.json diff --git a/package.json b/package.json index 80af3249a..e43bb3ed9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metamask-crx", - "version": "10.6.4", + "version": "10.7.0", "private": true, "repository": { "type": "git", @@ -12,7 +12,7 @@ "start": "yarn build:dev dev", "start:lavamoat": "yarn build dev", "dist": "yarn build prod", - "build": "lavamoat development/build/index.js", + "build": "yarn lavamoat:build", "build:dev": "node development/build/index.js", "start:test": "yarn build testDev", "benchmark:chrome": "SELENIUM_BROWSER=chrome node test/e2e/benchmark.js", @@ -41,8 +41,9 @@ "test:coverage:path": "nyc --check-coverage yarn test:unit:path", "ganache:start": "./development/run-ganache.sh", "sentry:publish": "node ./development/sentry-publish.js", - "lint": "prettier --check '**/*.json' && eslint . --ext js,snap --cache && yarn lint:styles", - "lint:fix": "prettier --write '**/*.json' && eslint . --ext js --cache --fix", + "lint:prettier": "prettier '**/*.json'", + "lint": "yarn lint:prettier --check '**/*.json' && eslint . --ext js,snap --cache && yarn lint:styles", + "lint:fix": "yarn lint:prettier --write '**/*.json' && eslint . --ext js --cache --fix", "lint:changed": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' | tr '\\n' '\\0' | xargs -0 eslint", "lint:changed:fix": "{ git ls-files --others --exclude-standard ; git diff-index --name-only --diff-filter=d HEAD ; } | grep --regexp='[.]js$' | tr '\\n' '\\0' | xargs -0 eslint --fix", "lint:changelog": "auto-changelog validate", @@ -63,9 +64,10 @@ "storybook:deploy": "storybook-to-ghpages --existing-output-dir storybook-build --remote storybook --branch master", "update-changelog": "auto-changelog update", "generate:migration": "./development/generate-migration.sh", - "lavamoat:build:auto": "lavamoat ./development/build/index.js --writeAutoPolicy", - "lavamoat:debug:build": "lavamoat ./development/build/index.js --writeAutoPolicyDebug", - "lavamoat:background:auto": "WRITE_AUTO_POLICY=1 yarn build prod", + "lavamoat:build": "lavamoat development/build/index.js --policy lavamoat/build-system/policy.json --policyOverride lavamoat/build-system/policy-override.json", + "lavamoat:build:auto": "yarn lavamoat:build --writeAutoPolicy", + "lavamoat:debug:build": "yarn lavamoat:build --writeAutoPolicyDebug --policydebug lavamoat/build-system/policy-debug.json", + "lavamoat:background:auto": "./development/generate-lavamoat-policies.sh", "lavamoat:auto": "yarn lavamoat:build:auto && yarn lavamoat:background:auto" }, "resolutions": { @@ -136,7 +138,7 @@ "eth-ens-namehash": "^2.0.8", "eth-json-rpc-filters": "^4.2.1", "eth-json-rpc-infura": "^5.1.0", - "eth-json-rpc-middleware": "^6.0.0", + "eth-json-rpc-middleware": "^8.0.0", "eth-keyring-controller": "^6.2.0", "eth-lattice-keyring": "^0.4.0", "eth-method-registry": "^2.0.0", @@ -222,7 +224,7 @@ "@babel/preset-react": "^7.0.0", "@babel/register": "^7.5.5", "@lavamoat/allow-scripts": "^1.0.6", - "@lavamoat/lavapack": "^2.0.3", + "@lavamoat/lavapack": "^2.0.4", "@metamask/auto-changelog": "^2.1.0", "@metamask/eslint-config": "^6.0.0", "@metamask/eslint-config-jest": "^6.0.0", diff --git a/shared/constants/metametrics.js b/shared/constants/metametrics.js index 7f0a3804f..948a3d8d7 100644 --- a/shared/constants/metametrics.js +++ b/shared/constants/metametrics.js @@ -140,3 +140,7 @@ export const METAMETRICS_BACKGROUND_PAGE_OBJECT = { * @property {() => void} identify - Identify an anonymous user. We do not * currently use this method. */ + +export const REJECT_NOTFICIATION_CLOSE = 'Cancel Via Notification Close'; +export const REJECT_NOTFICIATION_CLOSE_SIG = + 'Cancel Sig Request Via Notification Close'; diff --git a/shared/constants/network.js b/shared/constants/network.js index a85f544a7..2210605d0 100644 --- a/shared/constants/network.js +++ b/shared/constants/network.js @@ -161,3 +161,13 @@ export const CHAIN_ID_TO_GAS_LIMIT_BUFFER_MAP = { [OPTIMISM_CHAIN_ID]: 1, [OPTIMISM_TESTNET_CHAIN_ID]: 1, }; + +/** + * Ethereum JSON-RPC methods that are known to exist but that we intentionally + * do not support. + */ +export const UNSUPPORTED_RPC_METHODS = new Set([ + // This is implemented later in our middleware stack – specifically, in + // eth-json-rpc-middleware – but our UI does not support it. + 'eth_signTransaction', +]); diff --git a/test/data/mock-state.json b/test/data/mock-state.json index e8c979fd1..9adeaea9b 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -160,6 +160,10 @@ "toNickname": "" }, "useTokenDetection": true, + "advancedGasFee": { + "maxBaseFee": "1.5", + "priorityFee": "2" + }, "tokenList": { "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599": { "address": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", diff --git a/test/e2e/tests/from-import-ui.spec.js b/test/e2e/tests/from-import-ui.spec.js index 0bd3b683a..a83a9bbbb 100644 --- a/test/e2e/tests/from-import-ui.spec.js +++ b/test/e2e/tests/from-import-ui.spec.js @@ -27,38 +27,72 @@ describe('Metamask Import UI', function () { async ({ driver }) => { await driver.navigate(); - // clicks the continue button on the welcome screen - await driver.findElement('.welcome-page__header'); - await driver.clickElement({ - text: enLocaleMessages.getStarted.message, - tag: 'button', - }); + if (process.env.ONBOARDING_V2 === '1') { + // welcome + await driver.clickElement('[data-testid="onboarding-import-wallet"]'); - // clicks the "Import Wallet" option - await driver.clickElement({ text: 'Import wallet', tag: 'button' }); + // metrics + await driver.clickElement('[data-testid="metametrics-no-thanks"]'); - // clicks the "No thanks" option on the metametrics opt-in screen - await driver.clickElement('.btn-secondary'); + // import with recovery phrase + await driver.fill('[data-testid="import-srp-text"]', testSeedPhrase); + await driver.clickElement('[data-testid="import-srp-confirm"]'); - // Import Secret Recovery Phrase - await driver.fill( - 'input[placeholder="Paste Secret Recovery Phrase from clipboard"]', - testSeedPhrase, - ); + // create password + await driver.fill( + '[data-testid="create-password-new"]', + 'correct horse battery staple', + ); + await driver.fill( + '[data-testid="create-password-confirm"]', + 'correct horse battery staple', + ); + await driver.clickElement('[data-testid="create-password-terms"]'); + await driver.clickElement('[data-testid="create-password-import"]'); - await driver.fill('#password', 'correct horse battery staple'); - await driver.fill('#confirm-password', 'correct horse battery staple'); + // complete + await driver.clickElement('[data-testid="onboarding-complete-done"]'); - await driver.clickElement('.first-time-flow__terms'); + // pin extension + await driver.clickElement('[data-testid="pin-extension-next"]'); + await driver.clickElement('[data-testid="pin-extension-done"]'); + } else { + // clicks the continue button on the welcome screen + await driver.findElement('.welcome-page__header'); + await driver.clickElement({ + text: enLocaleMessages.getStarted.message, + tag: 'button', + }); - await driver.clickElement({ text: 'Import', tag: 'button' }); + // clicks the "Import Wallet" option + await driver.clickElement({ text: 'Import wallet', tag: 'button' }); - // clicks through the success screen - await driver.findElement({ text: 'Congratulations', tag: 'div' }); - await driver.clickElement({ - text: enLocaleMessages.endOfFlowMessage10.message, - tag: 'button', - }); + // clicks the "No thanks" option on the metametrics opt-in screen + await driver.clickElement('.btn-secondary'); + + // Import Secret Recovery Phrase + await driver.fill( + 'input[placeholder="Paste Secret Recovery Phrase from clipboard"]', + testSeedPhrase, + ); + + await driver.fill('#password', 'correct horse battery staple'); + await driver.fill( + '#confirm-password', + 'correct horse battery staple', + ); + + await driver.clickElement('.first-time-flow__terms'); + + await driver.clickElement({ text: 'Import', tag: 'button' }); + + // clicks through the success screen + await driver.findElement({ text: 'Congratulations', tag: 'div' }); + await driver.clickElement({ + text: enLocaleMessages.endOfFlowMessage10.message, + tag: 'button', + }); + } // Show account information await driver.clickElement( @@ -233,10 +267,15 @@ describe('Metamask Import UI', function () { // should remove the account await driver.clickElement({ text: 'Remove', tag: 'button' }); - const currentActiveAccountName = await driver.findElement( - '.selected-account__name', + // Wait until selected account switches away from removed account to first account + await driver.waitForSelector( + { + css: '.selected-account__name', + text: 'Account 1', + }, + { timeout: 10000 }, ); - assert.equal(await currentActiveAccountName.getText(), 'Account 1'); + await driver.delay(regularDelayMs); await driver.clickElement('.account-menu__icon'); diff --git a/test/e2e/tests/metamask-responsive-ui.spec.js b/test/e2e/tests/metamask-responsive-ui.spec.js index e512ce9f4..adb5ad644 100644 --- a/test/e2e/tests/metamask-responsive-ui.spec.js +++ b/test/e2e/tests/metamask-responsive-ui.spec.js @@ -16,50 +16,6 @@ describe('Metamask Responsive UI', function () { async ({ driver }) => { await driver.navigate(); - // clicks the continue button on the welcome screen - await driver.findElement('.welcome-page__header'); - await driver.clickElement({ - text: enLocaleMessages.getStarted.message, - tag: 'button', - }); - await driver.delay(tinyDelayMs); - - // clicks the "Create New Wallet" option - await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); - - // clicks the "I Agree" option on the metametrics opt-in screen - await driver.clickElement('.btn-primary'); - - // accepts a secure password - await driver.fill( - '.first-time-flow__form #create-password', - 'correct horse battery staple', - ); - await driver.fill( - '.first-time-flow__form #confirm-password', - 'correct horse battery staple', - ); - await driver.clickElement('.first-time-flow__checkbox'); - await driver.clickElement('.first-time-flow__form button'); - - // renders the Secret Recovery Phrase intro screen - await driver.clickElement('.seed-phrase-intro__left button'); - - // reveals the Secret Recovery Phrase - await driver.clickElement( - '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', - ); - const revealedSeedPhrase = await driver.findElement( - '.reveal-seed-phrase__secret-words', - ); - const seedPhrase = await revealedSeedPhrase.getText(); - assert.equal(seedPhrase.split(' ').length, 12); - - await driver.clickElement({ - text: enLocaleMessages.next.message, - tag: 'button', - }); - async function clickWordAndWait(word) { await driver.clickElement( `[data-testid="seed-phrase-sorted"] [data-testid="draggable-seed-${word}"]`, @@ -67,26 +23,126 @@ describe('Metamask Responsive UI', function () { await driver.delay(tinyDelayMs); } - // can retype the Secret Recovery Phrase - const words = seedPhrase.split(' '); - for (const word of words) { - await clickWordAndWait(word); + if (process.env.ONBOARDING_V2 === '1') { + // welcome + await driver.clickElement('[data-testid="onboarding-create-wallet"]'); + + // metrics + await driver.clickElement('[data-testid="metametrics-no-thanks"]'); + + // create password + await driver.fill( + '[data-testid="create-password-new"]', + 'correct horse battery staple', + ); + await driver.fill( + '[data-testid="create-password-confirm"]', + 'correct horse battery staple', + ); + await driver.clickElement('[data-testid="create-password-terms"]'); + await driver.clickElement('[data-testid="create-password-wallet"]'); + + // secure wallet + await driver.clickElement( + '[data-testid="secure-wallet-recommended"]', + ); + + // review + await driver.clickElement('[data-testid="recovery-phrase-reveal"]'); + const chipTwo = await ( + await driver.findElement('[data-testid="recovery-phrase-chip-2"]') + ).getText(); + const chipThree = await ( + await driver.findElement('[data-testid="recovery-phrase-chip-3"]') + ).getText(); + const chipSeven = await ( + await driver.findElement('[data-testid="recovery-phrase-chip-7"]') + ).getText(); + await driver.clickElement('[data-testid="recovery-phrase-next"]'); + + // confirm + await driver.fill('[data-testid="recovery-phrase-input-2"]', chipTwo); + await driver.fill( + '[data-testid="recovery-phrase-input-3"]', + chipThree, + ); + await driver.fill( + '[data-testid="recovery-phrase-input-7"]', + chipSeven, + ); + await driver.clickElement('[data-testid="recovery-phrase-confirm"]'); + + // complete + await driver.clickElement('[data-testid="onboarding-complete-done"]'); + + // pin extension + await driver.clickElement('[data-testid="pin-extension-next"]'); + await driver.clickElement('[data-testid="pin-extension-done"]'); + } else { + // clicks the continue button on the welcome screen + await driver.findElement('.welcome-page__header'); + await driver.clickElement({ + text: enLocaleMessages.getStarted.message, + tag: 'button', + }); + await driver.delay(tinyDelayMs); + + // clicks the "Create New Wallet" option + await driver.clickElement({ text: 'Create a Wallet', tag: 'button' }); + + // clicks the "I Agree" option on the metametrics opt-in screen + await driver.clickElement('.btn-primary'); + + // accepts a secure password + await driver.fill( + '.first-time-flow__form #create-password', + 'correct horse battery staple', + ); + await driver.fill( + '.first-time-flow__form #confirm-password', + 'correct horse battery staple', + ); + await driver.clickElement('.first-time-flow__checkbox'); + await driver.clickElement('.first-time-flow__form button'); + + // renders the Secret Recovery Phrase intro screen + await driver.clickElement('.seed-phrase-intro__left button'); + + // reveals the Secret Recovery Phrase + await driver.clickElement( + '.reveal-seed-phrase__secret-blocker .reveal-seed-phrase__reveal-button', + ); + const revealedSeedPhrase = await driver.findElement( + '.reveal-seed-phrase__secret-words', + ); + const seedPhrase = await revealedSeedPhrase.getText(); + assert.equal(seedPhrase.split(' ').length, 12); + + await driver.clickElement({ + text: enLocaleMessages.next.message, + tag: 'button', + }); + + // can retype the Secret Recovery Phrase + const words = seedPhrase.split(' '); + for (const word of words) { + await clickWordAndWait(word); + } + await driver.clickElement({ text: 'Confirm', tag: 'button' }); + + // clicks through the success screen + await driver.findElement({ text: 'Congratulations', tag: 'div' }); + await driver.clickElement({ + text: enLocaleMessages.endOfFlowMessage10.message, + tag: 'button', + }); } - await driver.clickElement({ text: 'Confirm', tag: 'button' }); - // clicks through the success screen - await driver.findElement({ text: 'Congratulations', tag: 'div' }); - await driver.clickElement({ - text: enLocaleMessages.endOfFlowMessage10.message, - tag: 'button', - }); - - // Show account information - // balance renders - await driver.waitForSelector({ - css: '[data-testid="eth-overview__primary-currency"]', - text: '0 ETH', - }); + // assert balance + const balance = await driver.findElement( + '[data-testid="wallet-balance"]', + ); + assert.ok(/^0\sETH$/u.test(await balance.getText())); }, ); }); diff --git a/test/e2e/tests/provider-events.spec.js b/test/e2e/tests/provider-api.spec.js similarity index 50% rename from test/e2e/tests/provider-events.spec.js rename to test/e2e/tests/provider-api.spec.js index 2f5f03b31..c2c5928f7 100644 --- a/test/e2e/tests/provider-events.spec.js +++ b/test/e2e/tests/provider-api.spec.js @@ -1,17 +1,19 @@ const { strict: assert } = require('assert'); +const { errorCodes } = require('eth-rpc-errors'); const { withFixtures } = require('../helpers'); describe('MetaMask', function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: 25000000000000000000, + }, + ], + }; + it('provider should inform dapp when switching networks', async function () { - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: 25000000000000000000, - }, - ], - }; await withFixtures( { dapp: true, @@ -62,4 +64,48 @@ describe('MetaMask', function () { }, ); }); + + it('should reject unsupported methods', async function () { + await withFixtures( + { + dapp: true, + failOnConsoleError: false, + fixtures: 'connected-state', + ganacheOptions, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.openNewPage('http://127.0.0.1:8080/'); + for (const unsupportedMethod of ['eth_signTransaction']) { + assert.equal( + await driver.executeAsyncScript(` + const webDriverCallback = arguments[arguments.length - 1]; + window.ethereum.request({ method: '${unsupportedMethod}' }) + .then(() => { + console.error('The unsupported method "${unsupportedMethod}" was not rejected.'); + webDriverCallback(false); + }) + .catch((error) => { + if (error.code === ${errorCodes.rpc.methodNotSupported}) { + webDriverCallback(true); + } + + console.error( + 'The unsupported method "${unsupportedMethod}" was rejected with an unexpected error.', + error, + ); + webDriverCallback(false); + }) + `), + true, + `The unsupported method "${unsupportedMethod}" should be rejected by the provider.`, + ); + } + }, + ); + }); }); diff --git a/test/e2e/webdriver/driver.js b/test/e2e/webdriver/driver.js index 0b6cfef4d..dbe9fb21a 100644 --- a/test/e2e/webdriver/driver.js +++ b/test/e2e/webdriver/driver.js @@ -29,6 +29,10 @@ function wrapElementWithAPI(element, driver) { return element; } +/** + * For Selenium WebDriver API documentation, see: + * https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html + */ class Driver { /** * @param {!ThenableWebDriver} driver - A {@code WebDriver} instance @@ -49,6 +53,10 @@ class Driver { }; } + async executeAsyncScript(script, ...args) { + return this.driver.executeAsyncScript(script, args); + } + async executeScript(script, ...args) { return this.driver.executeScript(script, args); } diff --git a/test/stub/provider.js b/test/stub/provider.js index 7f84e795f..da618f4c7 100644 --- a/test/stub/provider.js +++ b/test/stub/provider.js @@ -1,6 +1,5 @@ -import { JsonRpcEngine } from 'json-rpc-engine'; -import scaffoldMiddleware from 'eth-json-rpc-middleware/scaffold'; -import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware'; +import { JsonRpcEngine, createScaffoldMiddleware } from 'json-rpc-engine'; +import { providerAsMiddleware } from 'eth-json-rpc-middleware'; import GanacheCore from 'ganache-core'; export function getTestSeed() { @@ -45,7 +44,7 @@ export function providerFromEngine(engine) { export function createTestProviderTools(opts = {}) { const engine = createEngineForTestData(); // handle provided hooks - engine.push(scaffoldMiddleware(opts.scaffold || {})); + engine.push(createScaffoldMiddleware(opts.scaffold || {})); // handle block tracker methods engine.push( providerAsMiddleware( diff --git a/ui/components/app/confirm-page-container/confirm-page-container-container.test.js b/ui/components/app/confirm-page-container/confirm-page-container-container.test.js index 9ddf77de8..fc0a5f669 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-container.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-container.test.js @@ -10,6 +10,14 @@ import ConfirmPageContainer, { ConfirmPageContainerNavigation, } from '.'; +jest.mock('../../../store/actions', () => ({ + disconnectGasFeeEstimatePoller: jest.fn(), + getGasFeeEstimatesAndStartPolling: jest + .fn() + .mockImplementation(() => Promise.resolve()), + addPollingTokenToAppState: jest.fn(), +})); + describe('Confirm Page Container Container Test', () => { let wrapper; @@ -31,6 +39,8 @@ describe('Confirm Page Container Container Test', () => { selectedAddress: '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5', addressBook: [], chainId: 'test', + identities: [], + featureFlags: {}, }, }; diff --git a/ui/components/app/confirm-page-container/confirm-page-container.component.js b/ui/components/app/confirm-page-container/confirm-page-container.component.js index 7a4eb0e10..117318e3d 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container.component.js @@ -4,6 +4,7 @@ import SenderToRecipient from '../../ui/sender-to-recipient'; import { PageContainerFooter } from '../../ui/page-container'; import EditGasPopover from '../edit-gas-popover'; import { EDIT_GAS_MODES } from '../../../../shared/constants/gas'; +import { GasFeeContextProvider } from '../../../contexts/gasFee'; import ErrorMessage from '../../ui/error-message'; import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction'; import Dialog from '../../ui/dialog'; @@ -135,102 +136,104 @@ export default class ConfirmPageContainer extends Component { currentTransaction.txParams?.value === '0x0'; return ( -
- onNextTx(txId)} - firstTx={firstTx} - lastTx={lastTx} - ofText={ofText} - requestsWaitingText={requestsWaitingText} - /> - onEdit()} - showAccountInHeader={showAccountInHeader} - accountAddress={fromAddress} - > - {hideSenderToRecipient ? null : ( - +
+ onNextTx(txId)} + firstTx={firstTx} + lastTx={lastTx} + ofText={ofText} + requestsWaitingText={requestsWaitingText} + /> + onEdit()} + showAccountInHeader={showAccountInHeader} + accountAddress={fromAddress} + > + {hideSenderToRecipient ? null : ( + + )} + +
+ {showAddToAddressDialog && ( + showAddToAddressBookModal()} + > + {this.context.t('newAccountDetectedDialogMessage')} + + )} +
+ {contentComponent || ( + )} - -
- {showAddToAddressDialog && ( - showAddToAddressBookModal()} + {shouldDisplayWarning && ( +
+ +
+ )} + {contentComponent && ( + - {this.context.t('newAccountDetectedDialogMessage')} -
+ {unapprovedTxCount > 1 && ( + + {this.context.t('rejectTxsN', [unapprovedTxCount])} + + )} + + )} + {editingGas && ( + )}
- {contentComponent || ( - - )} - {shouldDisplayWarning && ( -
- -
- )} - {contentComponent && ( - - {unapprovedTxCount > 1 && ( - - {this.context.t('rejectTxsN', [unapprovedTxCount])} - - )} - - )} - {editingGas && ( - - )} -
+ ); } } diff --git a/ui/components/app/gas-timing/gas-timing.component.js b/ui/components/app/gas-timing/gas-timing.component.js index 972805ffb..41fc6bed5 100644 --- a/ui/components/app/gas-timing/gas-timing.component.js +++ b/ui/components/app/gas-timing/gas-timing.component.js @@ -24,6 +24,7 @@ import InfoTooltip from '../../ui/info-tooltip/info-tooltip'; import { getGasFeeTimeEstimate } from '../../../store/actions'; import { GAS_FORM_ERRORS } from '../../../helpers/constants/gas'; +import { useGasFeeContext } from '../../../contexts/gasFee'; // Once we reach this second threshold, we switch to minutes as a unit const SECOND_CUTOFF = 90; @@ -49,6 +50,7 @@ export default function GasTiming({ const [customEstimatedTime, setCustomEstimatedTime] = useState(null); const t = useContext(I18nContext); + const { estimateToUse } = useGasFeeContext(); // If the user has chosen a value lower than the low gas fee estimate, // We'll need to use the useEffect hook below to make a call to calculate @@ -94,12 +96,17 @@ export default function GasTiming({ previousIsUnknownLow, ]); - const unknownProcessingTimeText = ( - <> - {t('editGasTooLow')}{' '} - - - ); + let unknownProcessingTimeText; + if (EIP_1559_V2) { + unknownProcessingTimeText = t('editGasTooLow'); + } else { + unknownProcessingTimeText = ( + <> + {t('editGasTooLow')}{' '} + + + ); + } if ( gasWarnings?.maxPriorityFee === GAS_FORM_ERRORS.MAX_PRIORITY_FEE_TOO_LOW || @@ -148,8 +155,9 @@ export default function GasTiming({ ]); } } else { - attitude = 'negative'; - + if (!EIP_1559_V2 || estimateToUse === 'low') { + attitude = 'negative'; + } // If the user has chosen a value less than our low estimate, // calculate a potential wait time if (isUnknownLow) { @@ -191,7 +199,8 @@ export default function GasTiming({ {text} diff --git a/ui/components/app/gas-timing/index.scss b/ui/components/app/gas-timing/index.scss index 52b0f58c1..20d0b451f 100644 --- a/ui/components/app/gas-timing/index.scss +++ b/ui/components/app/gas-timing/index.scss @@ -14,6 +14,11 @@ font-weight: bold; } + &--negative-V2 { + color: $secondary-1; + font-weight: bold; + } + .info-tooltip { display: inline-block; margin-inline-start: 4px; diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.component.js b/ui/components/app/modals/account-details-modal/account-details-modal.component.js index 858fc5999..1df675a01 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.component.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.component.js @@ -84,9 +84,7 @@ export default class AccountDetailsModal extends Component { ? this.context.t('blockExplorerView', [ getURLHostName(rpcPrefs.blockExplorerUrl), ]) - : this.context.t('viewOnEtherscan', [ - this.context.t('blockExplorerAccountAction'), - ])} + : this.context.t('etherscanViewOn')} {exportPrivateKeyFeatureEnabled ? ( diff --git a/ui/components/app/modals/account-details-modal/index.scss b/ui/components/app/modals/account-details-modal/index.scss index ecab51311..3eedab80c 100644 --- a/ui/components/app/modals/account-details-modal/index.scss +++ b/ui/components/app/modals/account-details-modal/index.scss @@ -8,13 +8,13 @@ & &__button { margin-top: 17px; padding: 10px 22px; - width: 286px; + width: 284px; } &__divider { width: 100%; height: 1px; - margin: 19px 0 8px 0; + margin: 16px 0 8px 0; background-color: $alto; } diff --git a/ui/components/app/modals/modal.js b/ui/components/app/modals/modal.js index 16a5d4807..c31cba238 100644 --- a/ui/components/app/modals/modal.js +++ b/ui/components/app/modals/modal.js @@ -64,7 +64,7 @@ const accountModalStyle = { margin: '0 auto', }, laptopModalStyle: { - width: '360px', + width: '335px', // top: 'calc(33% + 45px)', boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', borderRadius: '4px', diff --git a/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js b/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js index 6dc671c89..22368d146 100644 --- a/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js +++ b/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js @@ -14,6 +14,7 @@ export default function MultilayerFeeMessage({ transaction, layer2fee, nativeCurrency, + plainStyle, }) { const t = useContext(I18nContext); @@ -57,12 +58,16 @@ export default function MultilayerFeeMessage({ key="total-item" detailTitle={t('layer1Fees')} detailTotal={layer1Total} + noBold={plainStyle} + flexWidthValues={plainStyle} /> ); @@ -72,4 +77,5 @@ MultilayerFeeMessage.propTypes = { transaction: PropTypes.object, layer2fee: PropTypes.string, nativeCurrency: PropTypes.string, + plainStyle: PropTypes.bool, }; diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js index a8233fc98..2ee7d005f 100644 --- a/ui/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/components/app/signature-request-original/signature-request-original.component.js @@ -5,11 +5,7 @@ import classnames from 'classnames'; import { ObjectInspector } from 'react-inspector'; import LedgerInstructionField from '../ledger-instruction-field'; -import { - ENVIRONMENT_TYPE_NOTIFICATION, - MESSAGE_TYPE, -} from '../../../../shared/constants/app'; -import { getEnvironmentType } from '../../../../app/scripts/lib/util'; +import { MESSAGE_TYPE } from '../../../../shared/constants/app'; import Identicon from '../../ui/identicon'; import AccountListItem from '../account-list-item'; import { conversionUtil } from '../../../../shared/modules/conversion.utils'; @@ -39,42 +35,13 @@ export default class SignatureRequestOriginal extends Component { domainMetadata: PropTypes.object, hardwareWalletRequiresConnection: PropTypes.bool, isLedgerWallet: PropTypes.bool, + nativeCurrency: PropTypes.string.isRequired, }; state = { fromAccount: this.props.fromAccount, }; - componentDidMount = () => { - if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { - window.addEventListener('beforeunload', this._beforeUnload); - } - }; - - componentWillUnmount = () => { - this._removeBeforeUnload(); - }; - - _beforeUnload = (event) => { - const { clearConfirmTransaction, cancel } = this.props; - const { metricsEvent } = this.context; - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Sign Request', - name: 'Cancel Sig Request Via Notification Close', - }, - }); - clearConfirmTransaction(); - cancel(event); - }; - - _removeBeforeUnload = () => { - if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { - window.removeEventListener('beforeunload', this._beforeUnload); - } - }; - renderHeader = () => { return (
@@ -108,12 +75,12 @@ export default class SignatureRequestOriginal extends Component { }; renderBalance = () => { - const { conversionRate } = this.props; + const { conversionRate, nativeCurrency } = this.props; const { fromAccount: { balance }, } = this.state; - const balanceInEther = conversionUtil(balance, { + const balanceInBaseAsset = conversionUtil(balance, { fromNumericBase: 'hex', toNumericBase: 'dec', fromDenomination: 'WEI', @@ -127,7 +94,7 @@ export default class SignatureRequestOriginal extends Component { {`${this.context.t('balance')}:`}
- {`${balanceInEther} ETH`} + {`${balanceInBaseAsset} ${nativeCurrency}`}
); @@ -300,7 +267,6 @@ export default class SignatureRequestOriginal extends Component { large className="request-signature__footer__cancel-button" onClick={async (event) => { - this._removeBeforeUnload(); await cancel(event); metricsEvent({ eventOpts: { @@ -325,7 +291,6 @@ export default class SignatureRequestOriginal extends Component { className="request-signature__footer__sign-button" disabled={hardwareWalletRequiresConnection} onClick={async (event) => { - this._removeBeforeUnload(); await sign(event); metricsEvent({ eventOpts: { diff --git a/ui/components/app/signature-request-original/signature-request-original.container.js b/ui/components/app/signature-request-original/signature-request-original.container.js index 82f313bd4..bcbc140bf 100644 --- a/ui/components/app/signature-request-original/signature-request-original.container.js +++ b/ui/components/app/signature-request-original/signature-request-original.container.js @@ -13,7 +13,10 @@ import { import { getAccountByAddress } from '../../../helpers/utils/util'; import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'; import { getMostRecentOverviewPage } from '../../../ducks/history/history'; -import { isAddressLedger } from '../../../ducks/metamask/metamask'; +import { + isAddressLedger, + getNativeCurrency, +} from '../../../ducks/metamask/metamask'; import SignatureRequestOriginal from './signature-request-original.component'; function mapStateToProps(state, ownProps) { @@ -34,6 +37,7 @@ function mapStateToProps(state, ownProps) { mostRecentOverviewPage: getMostRecentOverviewPage(state), hardwareWalletRequiresConnection, isLedgerWallet, + nativeCurrency: getNativeCurrency(state), // not passed to component allAccounts: accountsWithSendEtherInfoSelector(state), domainMetadata: getDomainMetadata(state), diff --git a/ui/components/app/signature-request/signature-request.component.js b/ui/components/app/signature-request/signature-request.component.js index 73d28ec26..4acfac4c0 100644 --- a/ui/components/app/signature-request/signature-request.component.js +++ b/ui/components/app/signature-request/signature-request.component.js @@ -1,12 +1,10 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import Identicon from '../../ui/identicon'; import LedgerInstructionField from '../ledger-instruction-field'; import Header from './signature-request-header'; import Footer from './signature-request-footer'; import Message from './signature-request-message'; -import { ENVIRONMENT_TYPE_NOTIFICATION } from './signature-request.constants'; export default class SignatureRequest extends PureComponent { static propTypes = { @@ -17,7 +15,6 @@ export default class SignatureRequest extends PureComponent { name: PropTypes.string, }).isRequired, isLedgerWallet: PropTypes.bool, - clearConfirmTransaction: PropTypes.func.isRequired, cancel: PropTypes.func.isRequired, sign: PropTypes.func.isRequired, hardwareWalletRequiresConnection: PropTypes.func.isRequired, @@ -28,33 +25,6 @@ export default class SignatureRequest extends PureComponent { metricsEvent: PropTypes.func, }; - componentDidMount() { - if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { - window.addEventListener('beforeunload', this._beforeUnload); - } - } - - _beforeUnload = (event) => { - const { - clearConfirmTransaction, - cancel, - txData: { type }, - } = this.props; - const { metricsEvent } = this.context; - metricsEvent({ - eventOpts: { - category: 'Transactions', - action: 'Sign Request', - name: 'Cancel Sig Request Via Notification Close', - }, - customVariables: { - type, - }, - }); - clearConfirmTransaction(); - cancel(event); - }; - formatWallet(wallet) { return `${wallet.slice(0, 8)}...${wallet.slice( wallet.length - 8, @@ -79,7 +49,6 @@ export default class SignatureRequest extends PureComponent { const { metricsEvent } = this.context; const onSign = (event) => { - window.removeEventListener('beforeunload', this._beforeUnload); sign(event); metricsEvent({ eventOpts: { @@ -95,7 +64,6 @@ export default class SignatureRequest extends PureComponent { }; const onCancel = (event) => { - window.removeEventListener('beforeunload', this._beforeUnload); cancel(event); metricsEvent({ eventOpts: { diff --git a/ui/components/app/signature-request/signature-request.container.js b/ui/components/app/signature-request/signature-request.container.js index 292bbbf73..11da8ab42 100644 --- a/ui/components/app/signature-request/signature-request.container.js +++ b/ui/components/app/signature-request/signature-request.container.js @@ -1,5 +1,4 @@ import { connect } from 'react-redux'; -import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'; import { accountsWithSendEtherInfoSelector, doesAddressRequireLedgerHidConnection, @@ -28,12 +27,6 @@ function mapStateToProps(state, ownProps) { }; } -function mapDispatchToProps(dispatch) { - return { - clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), - }; -} - function mergeProps(stateProps, dispatchProps, ownProps) { const { allAccounts, @@ -83,8 +76,4 @@ function mergeProps(stateProps, dispatchProps, ownProps) { }; } -export default connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, -)(SignatureRequest); +export default connect(mapStateToProps, null, mergeProps)(SignatureRequest); diff --git a/ui/components/app/transaction-detail-item/index.scss b/ui/components/app/transaction-detail-item/index.scss index 8d6c1bcd7..5fecb94e0 100644 --- a/ui/components/app/transaction-detail-item/index.scss +++ b/ui/components/app/transaction-detail-item/index.scss @@ -13,6 +13,17 @@ word-break: break-word; } + &__detail-values { + display: flex; + flex-wrap: wrap; + justify-content: end; + width: 55%; + + &--flex-width { + width: auto; + } + } + .info-tooltip { display: inline-block; margin-inline-start: 4px; diff --git a/ui/components/app/transaction-detail-item/transaction-detail-item.component.js b/ui/components/app/transaction-detail-item/transaction-detail-item.component.js index 80a3e2fef..84689bc95 100644 --- a/ui/components/app/transaction-detail-item/transaction-detail-item.component.js +++ b/ui/components/app/transaction-detail-item/transaction-detail-item.component.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import classnames from 'classnames'; import Typography from '../../ui/typography/typography'; import { @@ -15,26 +16,35 @@ export default function TransactionDetailItem({ detailTotal = '', subTitle = '', subText = '', + boldHeadings = true, + flexWidthValues = false, }) { return (
{detailTitle} {detailText && ( - - {detailText} - + + {detailText} + +
)} +
+ + {estimateUsed === 'custom' && onEdit && ( + + )} + {estimateUsed === 'dappSuggested' && ( + + + {t('dappSuggestedTooltip', [transaction.origin])} + + {supportsEIP1559 ? ( + <> + + {t('maxBaseFee')} + {maxFeePerGas} + + + {t('maxPriorityFee')} + {maxPriorityFeePerGas} + + + ) : ( + + {t('gasPriceLabel')} + {gasPrice} + + )} + + {t('gasLimit')} + {gasLimit} + +
+ } + position="top" + /> + )} +
+
{rows}
+ + ); + } return (
diff --git a/ui/components/app/transaction-detail/transaction-detail.component.test.js b/ui/components/app/transaction-detail/transaction-detail.component.test.js new file mode 100644 index 000000000..a95cf1565 --- /dev/null +++ b/ui/components/app/transaction-detail/transaction-detail.component.test.js @@ -0,0 +1,94 @@ +import React from 'react'; +import { screen } from '@testing-library/react'; + +import { ETH } from '../../../helpers/constants/common'; +import { GasFeeContextProvider } from '../../../contexts/gasFee'; +import { renderWithProvider } from '../../../../test/jest'; +import configureStore from '../../../store/store'; + +import TransactionDetail from './transaction-detail.component'; + +jest.mock('../../../store/actions', () => ({ + disconnectGasFeeEstimatePoller: jest.fn(), + getGasFeeEstimatesAndStartPolling: jest + .fn() + .mockImplementation(() => Promise.resolve()), + addPollingTokenToAppState: jest.fn(), +})); + +const render = (props) => { + const store = configureStore({ + metamask: { + nativeCurrency: ETH, + preferences: { + useNativeCurrencyAsPrimaryCurrency: true, + }, + provider: {}, + cachedBalances: {}, + accounts: { + '0xAddress': { + address: '0xAddress', + balance: '0x176e5b6f173ebe66', + }, + }, + selectedAddress: '0xAddress', + featureFlags: { advancedInlineGas: true }, + }, + }); + + return renderWithProvider( + + { + console.log('on edit'); + }} + rows={[]} + {...props} + /> + , + store, + ); +}; + +describe('TransactionDetail', () => { + beforeEach(() => { + process.env.EIP_1559_V2 = true; + }); + afterEach(() => { + process.env.EIP_1559_V2 = false; + }); + it('should render edit link with text low if low gas estimates are selected', () => { + render({ transaction: { userFeeLevel: 'low' } }); + expect(screen.queryByText('🐒')).toBeInTheDocument(); + expect(screen.queryByText('Low')).toBeInTheDocument(); + }); + it('should render edit link with text markey if medium gas estimates are selected', () => { + render({ transaction: { userFeeLevel: 'medium' } }); + expect(screen.queryByText('🦊')).toBeInTheDocument(); + expect(screen.queryByText('Market')).toBeInTheDocument(); + }); + it('should render edit link with text agressive if high gas estimates are selected', () => { + render({ transaction: { userFeeLevel: 'high' } }); + expect(screen.queryByText('🦍')).toBeInTheDocument(); + expect(screen.queryByText('Aggressive')).toBeInTheDocument(); + }); + it('should render edit link with text Site suggested if site suggested estimated are used', () => { + render({ + transaction: { + dappSuggestedGasFees: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 }, + txParams: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 }, + }, + }); + expect(screen.queryByText('🌐')).toBeInTheDocument(); + expect(screen.queryByText('Site suggested')).toBeInTheDocument(); + expect(document.getElementsByClassName('info-tooltip')).toHaveLength(1); + }); + it('should render edit link with text advance if custom gas estimates are used', () => { + render({ + defaultEstimateToUse: 'custom', + }); + expect(screen.queryByText('βš™')).toBeInTheDocument(); + expect(screen.queryByText('Advanced')).toBeInTheDocument(); + expect(screen.queryByText('Edit')).toBeInTheDocument(); + }); +}); diff --git a/ui/components/ui/card/README.mdx b/ui/components/ui/card/README.mdx new file mode 100644 index 000000000..88110ef1d --- /dev/null +++ b/ui/components/ui/card/README.mdx @@ -0,0 +1,42 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import Card from '.'; + +# Card + +Cards are used to group related content or actions together. + + + + + +## Component API + +The `Card` component extends the `Box` component. See the `Box` component for an extended list of props. + + + +## Usage + +The following describes the props and example usage for this component. + +### Padding, Border and Background Color + +The Card component has a set of default props that should meet most card use cases. There is a strong recommendation to not overwrite these to ensure our cards stay consistent across the app. + +That being said all props can be overwritten if necessary. + +```jsx +import { COLORS } from '../../../helpers/constants/design-system'; + +// To remove the border + +// All border related props of the Box component will work + +// To remove or change padding + +// All padding related props of the Box component will work + +// To change the background color + +``` diff --git a/ui/components/ui/card/card.component.js b/ui/components/ui/card/card.component.js deleted file mode 100644 index d75506b9a..000000000 --- a/ui/components/ui/card/card.component.js +++ /dev/null @@ -1,23 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; - -export default class Card extends PureComponent { - static propTypes = { - className: PropTypes.string, - overrideClassName: PropTypes.bool, - title: PropTypes.string, - children: PropTypes.node, - }; - - render() { - const { className, overrideClassName, title } = this.props; - - return ( -
-
{title}
- {this.props.children} -
- ); - } -} diff --git a/ui/components/ui/card/card.component.test.js b/ui/components/ui/card/card.component.test.js deleted file mode 100644 index 83205ec9c..000000000 --- a/ui/components/ui/card/card.component.test.js +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { shallow } from 'enzyme'; -import Card from './card.component'; - -describe('Card Component', () => { - it('should render a card with a title and child element', () => { - const wrapper = shallow( - -
Child
-
, - ); - - expect(wrapper.hasClass('card-test-class')).toStrictEqual(true); - const title = wrapper.find('.card__title'); - expect(title).toHaveLength(1); - expect(title.text()).toStrictEqual('Test'); - const child = wrapper.find('.child-test-class'); - expect(child).toHaveLength(1); - expect(child.text()).toStrictEqual('Child'); - }); -}); diff --git a/ui/components/ui/card/card.js b/ui/components/ui/card/card.js new file mode 100644 index 000000000..fc1beafaf --- /dev/null +++ b/ui/components/ui/card/card.js @@ -0,0 +1,60 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import Box from '../box'; +import { + BORDER_STYLE, + COLORS, + SIZES, +} from '../../../helpers/constants/design-system'; + +const Card = ({ + border = true, + padding = 4, + backgroundColor = COLORS.WHITE, + children, + ...props +}) => { + const defaultBorderProps = { + borderColor: border && COLORS.UI2, + borderRadius: border && SIZES.MD, + borderStyle: border && BORDER_STYLE.SOLID, + }; + + return ( + + {children} + + ); +}; + +Card.propTypes = { + /** + * Whether the Card has a border or not. + * Defaults to true + */ + border: PropTypes.bool, + /** + * Padding of the Card component accepts number or an array of 2 numbers. + * Defaults to 4 (16px) + */ + padding: Box.propTypes.padding, + /** + * The background color of the card + * Defaults to COLORS.WHITE + */ + backgroundColor: Box.propTypes.backgroundColor, + /** + * The Card component accepts all Box component props + */ + ...Box.propTypes, +}; + +export default Card; diff --git a/ui/components/ui/card/card.stories.js b/ui/components/ui/card/card.stories.js new file mode 100644 index 000000000..1dd2075e2 --- /dev/null +++ b/ui/components/ui/card/card.stories.js @@ -0,0 +1,169 @@ +import React from 'react'; +import { + ALIGN_ITEMS, + BLOCK_SIZES, + BORDER_STYLE, + COLORS, + DISPLAY, + JUSTIFY_CONTENT, + TEXT_ALIGN, +} from '../../../helpers/constants/design-system'; + +import README from './README.mdx'; +import Card from '.'; + +const sizeOptions = [undefined, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + +export default { + title: 'UI/Card', + id: __filename, + component: Card, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + children: { control: 'text' }, + border: { + control: 'boolean', + }, + borderStyle: { + control: { + type: 'select', + }, + options: Object.values(BORDER_STYLE), + }, + borderWidth: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + borderColor: { + control: { + type: 'select', + }, + options: Object.values(COLORS), + }, + backgroundColor: { + control: { + type: 'select', + }, + options: Object.values(COLORS), + }, + width: { + control: { + type: 'select', + }, + options: Object.values(BLOCK_SIZES), + }, + height: { + control: { + type: 'select', + }, + options: Object.values(BLOCK_SIZES), + }, + textAlign: { + control: { + type: 'select', + }, + options: Object.values(TEXT_ALIGN), + }, + margin: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + marginTop: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + marginRight: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + marginBottom: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + marginLeft: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + padding: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + paddingTop: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + paddingRight: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + paddingBottom: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + paddingLeft: { + control: { + type: 'select', + }, + options: [...sizeOptions], + }, + display: { + control: { + type: 'select', + }, + options: Object.values(DISPLAY), + }, + justifyContent: { + control: { + type: 'select', + }, + options: Object.values(JUSTIFY_CONTENT), + }, + alignItems: { + control: { + type: 'select', + }, + options: Object.values(ALIGN_ITEMS), + }, + }, + args: { + children: 'Card children', + }, +}; + +export const DefaultStory = (args) => {args.children}; + +DefaultStory.storyName = 'Default'; + +DefaultStory.args = { + padding: 4, + border: true, + borderWidth: 1, + borderColor: COLORS.UI2, + borderStyle: BORDER_STYLE.SOLID, + backgroundColor: COLORS.WHITE, + display: DISPLAY.BLOCK, +}; diff --git a/ui/components/ui/card/card.test.js b/ui/components/ui/card/card.test.js new file mode 100644 index 000000000..cbfd0db1c --- /dev/null +++ b/ui/components/ui/card/card.test.js @@ -0,0 +1,11 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import Card from '.'; + +describe('Card', () => { + it('should render the Card without crashing', () => { + const { getByText } = render(Card content); + + expect(getByText('Card content')).toBeDefined(); + }); +}); diff --git a/ui/components/ui/card/index.js b/ui/components/ui/card/index.js index 643fad74d..2c9f20524 100644 --- a/ui/components/ui/card/index.js +++ b/ui/components/ui/card/index.js @@ -1 +1 @@ -export { default } from './card.component'; +export { default } from './card'; diff --git a/ui/components/ui/card/index.scss b/ui/components/ui/card/index.scss deleted file mode 100644 index 4fa32e1bc..000000000 --- a/ui/components/ui/card/index.scss +++ /dev/null @@ -1,11 +0,0 @@ -.card { - border-radius: 4px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); - padding: 8px; - - &__title { - border-bottom: 1px solid #d8d8d8; - padding-bottom: 4px; - text-transform: capitalize; - } -} diff --git a/ui/components/ui/chip/README.mdx b/ui/components/ui/chip/README.mdx new file mode 100644 index 000000000..a873620d6 --- /dev/null +++ b/ui/components/ui/chip/README.mdx @@ -0,0 +1,15 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import Chip from '.'; + +# Chip + +Chips are compact elements that represent an input, status, or action. + + + + + +## Component API + + diff --git a/ui/components/ui/chip/chip-with-input.js b/ui/components/ui/chip/chip-with-input.js index c6fad92d9..8a5e30cc9 100644 --- a/ui/components/ui/chip/chip-with-input.js +++ b/ui/components/ui/chip/chip-with-input.js @@ -5,6 +5,7 @@ import { COLORS } from '../../../helpers/constants/design-system'; import Chip from '.'; export function ChipWithInput({ + dataTestId, className, borderColor = COLORS.UI1, inputValue, @@ -17,6 +18,7 @@ export function ChipWithInput({ > {setInputValue && ( { @@ -30,6 +32,7 @@ export function ChipWithInput({ } ChipWithInput.propTypes = { + dataTestId: PropTypes.string, borderColor: PropTypes.oneOf(Object.values(COLORS)), className: PropTypes.string, inputValue: PropTypes.string, diff --git a/ui/components/ui/chip/chip.js b/ui/components/ui/chip/chip.js index 6311ea72e..e23dd8289 100644 --- a/ui/components/ui/chip/chip.js +++ b/ui/components/ui/chip/chip.js @@ -6,9 +6,11 @@ import Typography from '../typography'; import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system'; export default function Chip({ + dataTestId, className, children, borderColor = COLORS.UI1, + backgroundColor, label, labelProps = {}, leftIcon, @@ -25,12 +27,14 @@ export default function Chip({ return (
, + }, + }, + rightIcon: { + control: { + type: 'select', + }, + options: ['Identicon'], + mapping: { + Identicon: ( + + ), + }, + }, + label: { + control: 'text', + }, + labelProps: { + color: { + control: { + type: 'select', + }, + options: Object.values(COLORS), + }, + variant: { + color: { + control: { + type: 'select', + }, + options: Object.values(TYPOGRAPHY), + }, + }, + }, + borderColor: { + control: { + type: 'select', + }, + options: Object.values(COLORS), + }, + backgroundColor: { + control: { + type: 'select', + }, + options: Object.values(COLORS), + }, + children: { + control: 'text', + }, + }, }; -export const Plain = ({ - leftIcon, - rightIcon, - label = 'Hello', - borderColor = COLORS.UI1, - fontColor = COLORS.BLACK, -}) => ( - -); +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; + +DefaultStory.args = { + label: 'Chip', + borderColor: COLORS.UI3, + backgroundColor: COLORS.UI1, + labelProps: { + color: COLORS.BLACK, + variant: TYPOGRAPHY.H6, + }, +}; export const WithLeftIcon = () => ( - } /> ); export const WithRightIcon = () => ( - ( ); export const WithBothIcons = () => ( - ( } /> ); -export const WithInput = () => { - const [inputValue, setInputValue] = useState(''); +export const WithInput = (args) => { + const [inputValue, setInputValue] = useState('Chip with input'); return ( ); }; + +WithInput.args = { + borderColor: COLORS.UI3, +}; diff --git a/ui/components/ui/form-field/form-field.js b/ui/components/ui/form-field/form-field.js index 19296b46a..5cd1fd5b6 100644 --- a/ui/components/ui/form-field/form-field.js +++ b/ui/components/ui/form-field/form-field.js @@ -16,6 +16,7 @@ import NumericInput from '../numeric-input/numeric-input.component'; import InfoTooltip from '../info-tooltip/info-tooltip'; export default function FormField({ + dataTestId, titleText, titleUnit, tooltipText, @@ -94,6 +95,7 @@ export default function FormField({ type={password ? 'password' : 'text'} autoFocus={autoFocus} disabled={disabled} + data-testid={dataTestId} /> )} {error && ( @@ -111,6 +113,7 @@ export default function FormField({ } FormField.propTypes = { + dataTestId: PropTypes.string, titleText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), titleUnit: PropTypes.string, tooltipText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), diff --git a/ui/components/ui/qr-code/index.scss b/ui/components/ui/qr-code/index.scss index c228ffeda..03ba8fc08 100644 --- a/ui/components/ui/qr-code/index.scss +++ b/ui/components/ui/qr-code/index.scss @@ -25,10 +25,41 @@ margin-bottom: 9px; } + &__address-container { + display: flex; + justify-content: center; + + &__tooltip-wrapper { + width: 100%; + } + + &:hover { + cursor: pointer; + + .qr-code__copy-icon__svg { + fill: $primary-1; + } + } + } + &__address { @include H7; - background-color: $ui-1; - padding: 12px; + background-color: $Grey-000; + width: 76%; + padding: 8px 12px; + word-break: break-all; + text-align: center; + } + + &__copy-icon { + height: 13px; + padding: 17px 0; + position: absolute; + right: 24px; + + &__svg { + fill: $ui-5; + } } } diff --git a/ui/components/ui/qr-code/qr-code.js b/ui/components/ui/qr-code/qr-code.js index 89ce505ab..69921e260 100644 --- a/ui/components/ui/qr-code/qr-code.js +++ b/ui/components/ui/qr-code/qr-code.js @@ -3,7 +3,11 @@ import React from 'react'; import qrCode from 'qrcode-generator'; import { connect } from 'react-redux'; import { isHexPrefixed } from 'ethereumjs-util'; +import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; +import Tooltip from '../tooltip'; +import CopyIcon from '../icon/copy-icon.component'; +import { useI18nContext } from '../../../hooks/useI18nContext'; export default connect(mapStateToProps)(QrCodeView); @@ -22,6 +26,8 @@ function QrCodeView(props) { const address = `${ isHexPrefixed(data) ? 'ethereum:' : '' }${toChecksumHexAddress(data)}`; + const [copied, handleCopy] = useCopyToClipboard(); + const t = useI18nContext(); const qrImage = qrCode(4, 'M'); qrImage.addData(address); qrImage.make(); @@ -50,7 +56,23 @@ function QrCodeView(props) { __html: qrImage.createTableTag(4), }} /> -
{toChecksumHexAddress(data)}
+ +
{ + handleCopy(toChecksumHexAddress(data)); + }} + > +
{toChecksumHexAddress(data)}
+
+ +
+
+
); } diff --git a/ui/components/ui/toggle-button/toggle-button.component.js b/ui/components/ui/toggle-button/toggle-button.component.js index 0acdd2ab4..c54f0bbd8 100644 --- a/ui/components/ui/toggle-button/toggle-button.component.js +++ b/ui/components/ui/toggle-button/toggle-button.component.js @@ -53,6 +53,12 @@ const ToggleButton = (props) => { return (
{ + if (e.key === 'Enter') { + onToggle(value); + } + }} className={classnames('toggle-button', `toggle-button--${modifier}`, { 'toggle-button--disabled': disabled, })} diff --git a/ui/components/ui/ui-components.scss b/ui/components/ui/ui-components.scss index 75cddcb90..6200bb21f 100644 --- a/ui/components/ui/ui-components.scss +++ b/ui/components/ui/ui-components.scss @@ -8,7 +8,6 @@ @import 'button-group/index'; @import 'button/buttons'; @import 'callout/callout'; -@import 'card/index'; @import 'check-box/index'; @import 'chip/chip'; @import 'circle-icon/index'; diff --git a/ui/contexts/gasFee.js b/ui/contexts/gasFee.js new file mode 100644 index 000000000..c7fe7f092 --- /dev/null +++ b/ui/contexts/gasFee.js @@ -0,0 +1,37 @@ +import React, { createContext, useContext } from 'react'; +import PropTypes from 'prop-types'; +import { useGasFeeInputs } from '../hooks/gasFeeInput/useGasFeeInputs'; + +export const GasFeeContext = createContext({}); + +export const GasFeeContextProvider = ({ + children, + defaultEstimateToUse, + transaction, + minimumGasLimit, + editGasMode, +}) => { + const gasFeeDetails = useGasFeeInputs( + defaultEstimateToUse, + transaction, + minimumGasLimit, + editGasMode, + ); + return ( + + {children} + + ); +}; + +export function useGasFeeContext() { + return useContext(GasFeeContext); +} + +GasFeeContextProvider.propTypes = { + children: PropTypes.node.isRequired, + defaultEstimateToUse: PropTypes.string, + transaction: PropTypes.object.isRequired, + minimumGasLimit: PropTypes.string, + editGasMode: PropTypes.string, +}; diff --git a/ui/css/design-system/colors.scss b/ui/css/design-system/colors.scss index bda23ce09..d76de5ef6 100644 --- a/ui/css/design-system/colors.scss +++ b/ui/css/design-system/colors.scss @@ -103,6 +103,7 @@ $ui-1: #f2f3f4; $ui-2: #d6d9dc; $ui-3: #bbc0c5; $ui-4: #6a737d; +$ui-5: #c4c4c4; $mainnet: #29b6af; $ropsten: #ff4a8d; @@ -116,6 +117,7 @@ $color-map: ( 'ui-2': $ui-2, 'ui-3': $ui-3, 'ui-4': $ui-4, + 'ui-5': $ui-5, 'white': $ui-white, 'black': $ui-black, 'grey': $ui-grey, diff --git a/ui/helpers/constants/routes.js b/ui/helpers/constants/routes.js index 7883647de..d1f1dcf3d 100644 --- a/ui/helpers/constants/routes.js +++ b/ui/helpers/constants/routes.js @@ -38,6 +38,7 @@ const AWAITING_SIGNATURES_ROUTE = '/swaps/awaiting-signatures'; const AWAITING_SWAP_ROUTE = '/swaps/awaiting-swap'; const SWAPS_ERROR_ROUTE = '/swaps/swaps-error'; const SWAPS_MAINTENANCE_ROUTE = '/swaps/maintenance'; +const ADD_COLLECTIBLE_ROUTE = '/add-collectible'; const INITIALIZE_ROUTE = '/initialize'; const INITIALIZE_WELCOME_ROUTE = '/initialize/welcome'; @@ -218,6 +219,7 @@ export { AWAITING_SIGNATURES_ROUTE, SWAPS_ERROR_ROUTE, SWAPS_MAINTENANCE_ROUTE, + ADD_COLLECTIBLE_ROUTE, ONBOARDING_ROUTE, ONBOARDING_HELP_US_IMPROVE_ROUTE, ONBOARDING_CREATE_PASSWORD_ROUTE, diff --git a/ui/helpers/constants/transactions.js b/ui/helpers/constants/transactions.js index 614f0329d..aeeda8bdf 100644 --- a/ui/helpers/constants/transactions.js +++ b/ui/helpers/constants/transactions.js @@ -19,3 +19,8 @@ export const TOKEN_CATEGORY_HASH = { [TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER]: true, [TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM]: true, }; + +export const TRANSACTION_ENVELOPE_TYPE_NAMES = { + FEE_MARKET: 'fee-market', + LEGACY: 'legacy', +}; diff --git a/ui/hooks/gasFeeInput/useGasFeeErrors.js b/ui/hooks/gasFeeInput/useGasFeeErrors.js index d477087d0..0300feec0 100644 --- a/ui/hooks/gasFeeInput/useGasFeeErrors.js +++ b/ui/hooks/gasFeeInput/useGasFeeErrors.js @@ -130,7 +130,10 @@ const getMaxFeeWarning = ( return undefined; }; -const getBalanceError = (minimumCostInHexWei, transaction, ethBalance) => { +const hasBalanceError = (minimumCostInHexWei, transaction, ethBalance) => { + if (minimumCostInHexWei === undefined || ethBalance === undefined) { + return false; + } const minimumTxCostInHexWei = addHexes( minimumCostInHexWei, transaction?.txParams?.value || '0x0', @@ -247,7 +250,7 @@ export function useGasFeeErrors({ ); const { balance: ethBalance } = useSelector(getSelectedAccount); - const balanceError = getBalanceError( + const balanceError = hasBalanceError( minimumCostInHexWei, transaction, ethBalance, diff --git a/ui/hooks/gasFeeInput/useGasFeeInputs.js b/ui/hooks/gasFeeInput/useGasFeeInputs.js index e67bd031f..51021cc42 100644 --- a/ui/hooks/gasFeeInput/useGasFeeInputs.js +++ b/ui/hooks/gasFeeInput/useGasFeeInputs.js @@ -1,13 +1,19 @@ import { useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; -import { getAdvancedInlineGasShown } from '../../selectors'; -import { hexToDecimal } from '../../helpers/utils/conversions.util'; -import { GAS_FORM_ERRORS } from '../../helpers/constants/gas'; import { - GAS_RECOMMENDATIONS, CUSTOM_GAS_ESTIMATE, + GAS_RECOMMENDATIONS, + EDIT_GAS_MODES, } from '../../../shared/constants/gas'; +import { GAS_FORM_ERRORS } from '../../helpers/constants/gas'; +import { areDappSuggestedAndTxParamGasFeesTheSame } from '../../helpers/utils/confirm-tx.util'; +import { + checkNetworkAndAccountSupports1559, + getAdvancedInlineGasShown, +} from '../../selectors'; +import { hexToDecimal } from '../../helpers/utils/conversions.util'; +import { isLegacyTransaction } from '../../helpers/utils/transactions.util'; import { useGasFeeEstimates } from '../useGasFeeEstimates'; import { useGasFeeErrors } from './useGasFeeErrors'; @@ -65,8 +71,12 @@ export function useGasFeeInputs( defaultEstimateToUse = GAS_RECOMMENDATIONS.MEDIUM, transaction, minimumGasLimit = '0x5208', - editGasMode, + editGasMode = EDIT_GAS_MODES.MODIFY_IN_PLACE, ) { + const supportsEIP1559 = + useSelector(checkNetworkAndAccountSupports1559) && + !isLegacyTransaction(transaction?.txParams); + // We need the gas estimates from the GasFeeController in the background. // Calling this hooks initiates polling for new gas estimates and returns the // current estimate. @@ -90,6 +100,13 @@ export function useGasFeeInputs( return defaultEstimateToUse; }); + const [ + isUsingDappSuggestedGasFees, + setIsUsingDappSuggestedGasFees, + ] = useState(() => + Boolean(areDappSuggestedAndTxParamGasFeesTheSame(transaction)), + ); + const [gasLimit, setGasLimit] = useState( Number(hexToDecimal(transaction?.txParams?.gas ?? '0x0')), ); @@ -191,6 +208,7 @@ export function useGasFeeInputs( setMaxPriorityFeePerGas(null); setGasPrice(null); setGasPriceHasBeenManuallySet(false); + setIsUsingDappSuggestedGasFees(false); }, [ setInternalEstimateToUse, @@ -199,6 +217,7 @@ export function useGasFeeInputs( setMaxPriorityFeePerGas, setGasPrice, setGasPriceHasBeenManuallySet, + setIsUsingDappSuggestedGasFees, ], ); @@ -226,6 +245,7 @@ export function useGasFeeInputs( ]); return { + transaction, maxFeePerGas, maxFeePerGasFiat, setMaxFeePerGas, @@ -243,6 +263,7 @@ export function useGasFeeInputs( estimatedMaximumNative, estimatedMinimumNative, isGasEstimatesLoading, + isUsingDappSuggestedGasFees, gasFeeEstimates, gasEstimateType, estimatedGasFeeTimeBounds, @@ -254,5 +275,6 @@ export function useGasFeeInputs( gasErrors, gasWarnings, hasGasErrors, + supportsEIP1559, }; } diff --git a/ui/pages/add-collectible/add-collectible.component.js b/ui/pages/add-collectible/add-collectible.component.js new file mode 100644 index 000000000..4bf0ecdb0 --- /dev/null +++ b/ui/pages/add-collectible/add-collectible.component.js @@ -0,0 +1,65 @@ +import React, { useState } from 'react'; +import { useHistory } from 'react-router-dom'; +import { useI18nContext } from '../../hooks/useI18nContext'; +import { DEFAULT_ROUTE } from '../../helpers/constants/routes'; + +import Box from '../../components/ui/box'; +import TextField from '../../components/ui/text-field'; +import PageContainer from '../../components/ui/page-container'; + +export default function AddCollectible() { + const t = useI18nContext(); + const history = useHistory(); + + const [address, setAddress] = useState(''); + const [tokenId, setTokenId] = useState(''); + + return ( + { + console.log( + `Adding collectible with ID: ${tokenId} and address ${address}`, + ); + history.push(DEFAULT_ROUTE); + }} + submitText={t('add')} + onCancel={() => { + history.push(DEFAULT_ROUTE); + }} + onClose={() => { + history.push(DEFAULT_ROUTE); + }} + disabled={false} + contentComponent={ + + + setAddress(e.target.value)} + fullWidth + autoFocus + margin="normal" + /> + + + setTokenId(e.target.value)} + fullWidth + margin="normal" + /> + + + } + /> + ); +} diff --git a/ui/pages/add-collectible/index.js b/ui/pages/add-collectible/index.js new file mode 100644 index 000000000..71b5d8dd5 --- /dev/null +++ b/ui/pages/add-collectible/index.js @@ -0,0 +1 @@ +export { default } from './add-collectible.component'; diff --git a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index a00a46e0d..47475b5a4 100644 --- a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -13,6 +13,7 @@ import Box from '../../../components/ui/box'; import Button from '../../../components/ui/button'; import MetaFoxLogo from '../../../components/ui/metafox-logo'; import Identicon from '../../../components/ui/identicon'; +import MultiLayerFeeMessage from '../../../components/app/multilayer-fee-message'; import CopyIcon from '../../../components/ui/icon/copy-icon.component'; import { TYPOGRAPHY, @@ -61,6 +62,8 @@ export default class ConfirmApproveContent extends Component { chainId: PropTypes.string, rpcPrefs: PropTypes.object, isContract: PropTypes.bool, + hexTransactionTotal: PropTypes.string, + isMultiLayerFeeNetwork: PropTypes.bool, }; state = { @@ -121,20 +124,40 @@ export default class ConfirmApproveContent extends Component { nativeCurrency, ethTransactionTotal, fiatTransactionTotal, + hexTransactionTotal, + txData, + isMultiLayerFeeNetwork, } = this.props; return (
-
- {t('feeAssociatedRequest')} -
-
-
- {formatCurrency(fiatTransactionTotal, currentCurrency)} + {isMultiLayerFeeNetwork ? ( +
+
+ {t('transactionDetailLayer2GasHeading')} + {`${ethTransactionTotal} ${nativeCurrency}`} +
+
-
- {`${ethTransactionTotal} ${nativeCurrency}`} -
-
+ ) : ( + <> +
+ {t('feeAssociatedRequest')} +
+
+
+ {formatCurrency(fiatTransactionTotal, currentCurrency)} +
+
+ {`${ethTransactionTotal} ${nativeCurrency}`} +
+
+ + )}
); } diff --git a/ui/pages/confirm-approve/confirm-approve-content/index.scss b/ui/pages/confirm-approve/confirm-approve-content/index.scss index 6422693e7..31bbd8458 100644 --- a/ui/pages/confirm-approve/confirm-approve-content/index.scss +++ b/ui/pages/confirm-approve/confirm-approve-content/index.scss @@ -254,12 +254,28 @@ color: #000; } - &__secondary-fee { + &__secondary-fee, + &__labelled-fee { @include H6; font-weight: normal; color: #8c8e94; } + + &__labelled-fee { + display: flex; + justify-content: space-between; + + h6.typography--h6 { + font-weight: normal; + } + } + } + + &__transaction-details-extra-content { + display: flex; + flex-flow: column; + width: 100%; } &__view-full-tx-button-wrapper { diff --git a/ui/pages/confirm-approve/confirm-approve.js b/ui/pages/confirm-approve/confirm-approve.js index a95f1ddf5..4d4aa1614 100644 --- a/ui/pages/confirm-approve/confirm-approve.js +++ b/ui/pages/confirm-approve/confirm-approve.js @@ -31,6 +31,7 @@ import { getNextSuggestedNonce, getCurrentChainId, getRpcPrefsForCurrentProvider, + getIsMultiLayerFeeNetwork, } from '../../selectors'; import { useApproveTransaction } from '../../hooks/useApproveTransaction'; @@ -64,6 +65,7 @@ export default function ConfirmApprove() { const customNonceValue = useSelector(getCustomNonceValue); const chainId = useSelector(getCurrentChainId); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); + const isMultiLayerFeeNetwork = useSelector(getIsMultiLayerFeeNetwork); const fromAddressIsLedger = useSelector(isAddressLedgerByFromAddress(from)); @@ -71,9 +73,11 @@ export default function ConfirmApprove() { currentNetworkTxList.find( ({ id }) => id === (Number(paramsTransactionId) || transactionId), ) || {}; - const { ethTransactionTotal, fiatTransactionTotal } = useSelector((state) => - transactionFeeSelector(state, transaction), - ); + const { + ethTransactionTotal, + fiatTransactionTotal, + hexTransactionTotal, + } = useSelector((state) => transactionFeeSelector(state, transaction)); const currentToken = (tokens && tokens.find(({ address }) => @@ -207,6 +211,7 @@ export default function ConfirmApprove() { nativeCurrency={nativeCurrency} ethTransactionTotal={ethTransactionTotal} fiatTransactionTotal={fiatTransactionTotal} + hexTransactionTotal={hexTransactionTotal} useNonceField={useNonceField} nextNonce={nextNonce} customNonceValue={customNonceValue} @@ -240,6 +245,7 @@ export default function ConfirmApprove() { chainId={chainId} rpcPrefs={rpcPrefs} isContract={isContract} + isMultiLayerFeeNetwork={isMultiLayerFeeNetwork} /> {showCustomizeGasPopover && ( { - if ( - getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION - ) { - window.addEventListener('beforeunload', this._beforeUnload); - } - }; - - componentWillUnmount = () => { - this._removeBeforeUnload(); - }; - - _beforeUnload = async (event) => { - const { - clearConfirmTransaction, - cancelDecryptMessage, - txData, - } = this.props; - const { metricsEvent } = this.context; - await cancelDecryptMessage(txData, event); - metricsEvent({ - eventOpts: { - category: 'Messages', - action: 'Decrypt Message Request', - name: 'Cancel Via Notification Close', - }, - }); - clearConfirmTransaction(); - }; - - _removeBeforeUnload = () => { - if ( - getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION - ) { - window.removeEventListener('beforeunload', this._beforeUnload); - } - }; - copyMessage = () => { copyToClipboard(this.state.rawMessage); this.context.metricsEvent({ @@ -300,7 +260,6 @@ export default class ConfirmDecryptMessage extends Component { large className="request-decrypt-message__footer__cancel-button" onClick={async (event) => { - this._removeBeforeUnload(); await cancelDecryptMessage(txData, event); metricsEvent({ eventOpts: { @@ -320,7 +279,6 @@ export default class ConfirmDecryptMessage extends Component { large className="request-decrypt-message__footer__sign-button" onClick={async (event) => { - this._removeBeforeUnload(); await decryptMessage(txData, event); metricsEvent({ eventOpts: { diff --git a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js index cf31ee051..97e2b8c46 100644 --- a/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js +++ b/ui/pages/confirm-encryption-public-key/confirm-encryption-public-key.component.js @@ -5,8 +5,6 @@ import AccountListItem from '../../components/app/account-list-item'; import Button from '../../components/ui/button'; import Identicon from '../../components/ui/identicon'; -import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../shared/constants/app'; -import { getEnvironmentType } from '../../../app/scripts/lib/util'; import { conversionUtil } from '../../../shared/modules/conversion.utils'; export default class ConfirmEncryptionPublicKey extends Component { @@ -33,44 +31,6 @@ export default class ConfirmEncryptionPublicKey extends Component { nativeCurrency: PropTypes.string.isRequired, }; - componentDidMount = () => { - if ( - getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION - ) { - window.addEventListener('beforeunload', this._beforeUnload); - } - }; - - componentWillUnmount = () => { - this._removeBeforeUnload(); - }; - - _beforeUnload = async (event) => { - const { - clearConfirmTransaction, - cancelEncryptionPublicKey, - txData, - } = this.props; - const { metricsEvent } = this.context; - await cancelEncryptionPublicKey(txData, event); - metricsEvent({ - eventOpts: { - category: 'Messages', - action: 'Encryption public key Request', - name: 'Cancel Via Notification Close', - }, - }); - clearConfirmTransaction(); - }; - - _removeBeforeUnload = () => { - if ( - getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION - ) { - window.removeEventListener('beforeunload', this._beforeUnload); - } - }; - renderHeader = () => { return (
@@ -203,7 +163,6 @@ export default class ConfirmEncryptionPublicKey extends Component { large className="request-encryption-public-key__footer__cancel-button" onClick={async (event) => { - this._removeBeforeUnload(); await cancelEncryptionPublicKey(txData, event); metricsEvent({ eventOpts: { @@ -223,7 +182,6 @@ export default class ConfirmEncryptionPublicKey extends Component { large className="request-encryption-public-key__footer__sign-button" onClick={async (event) => { - this._removeBeforeUnload(); await encryptionPublicKey(txData, event); this.context.metricsEvent({ eventOpts: { diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js index 40ad20744..fc2d7e29a 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -1,7 +1,5 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../shared/constants/app'; -import { getEnvironmentType } from '../../../app/scripts/lib/util'; import ConfirmPageContainer from '../../components/app/confirm-page-container'; import { isBalanceSufficient } from '../send/send.utils'; import { @@ -54,6 +52,7 @@ import Typography from '../../components/ui/typography/typography'; import { MIN_GAS_LIMIT_DEC } from '../send/send.constants'; import GasDetailsItem from './gas-details-item'; +import LowPriorityMessage from './low-priority-message'; // eslint-disable-next-line prefer-destructuring const EIP_1559_V2 = process.env.EIP_1559_V2; @@ -414,6 +413,7 @@ export default class ConfirmTransactionBase extends Component { return (
+ {EIP_1559_V2 && } this.handleEditGas()} rows={[ @@ -499,6 +499,7 @@ export default class ConfirmTransactionBase extends Component { type={PRIMARY} value={hexMinimumTransactionFee} hideLabel={!useNativeCurrencyAsPrimaryCurrency} + numberOfDecimals={isMultiLayerFeeNetwork ? 18 : 6} />
} @@ -823,11 +824,6 @@ export default class ConfirmTransactionBase extends Component { }; } - _beforeUnload = () => { - const { txData: { id } = {}, cancelTransaction } = this.props; - cancelTransaction({ id }); - }; - _beforeUnloadForGasPolling = () => { this._isMounted = false; if (this.state.pollingToken) { @@ -837,9 +833,6 @@ export default class ConfirmTransactionBase extends Component { }; _removeBeforeUnload = () => { - if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { - window.removeEventListener('beforeunload', this._beforeUnload); - } window.removeEventListener('beforeunload', this._beforeUnloadForGasPolling); }; @@ -863,10 +856,6 @@ export default class ConfirmTransactionBase extends Component { }, }); - if (getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION) { - window.addEventListener('beforeunload', this._beforeUnload); - } - getNextNonce(); if (toAddress) { tryReverseResolveAddress(toAddress); diff --git a/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js b/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js index b36951cd4..6ac1e0be0 100644 --- a/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js +++ b/ui/pages/confirm-transaction-base/gas-details-item/gas-details-item.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; import { COLORS } from '../../../helpers/constants/design-system'; import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; @@ -14,11 +15,12 @@ import InfoTooltip from '../../../components/ui/info-tooltip/info-tooltip'; import LoadingHeartBeat from '../../../components/ui/loading-heartbeat'; import TransactionDetailItem from '../../../components/app/transaction-detail-item/transaction-detail-item.component'; import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display'; +import { useGasFeeContext } from '../../../contexts/gasFee'; const HeartBeat = () => process.env.IN_TEST === 'true' ? null : ; -const GasDetailItem = ({ +const GasDetailsItem = ({ hexMaximumTransactionFee, hexMinimumTransactionFee, isMainnet, @@ -29,6 +31,8 @@ const GasDetailItem = ({ useNativeCurrencyAsPrimaryCurrency, }) => { const t = useI18nContext(); + const { estimateToUse } = useGasFeeContext(); + return ( } - position="top" + position="bottom" /> } @@ -88,9 +92,18 @@ const GasDetailItem = ({
} subText={t('editGasSubTextFee', [ - - - + + + + {estimateToUse === 'high' && '⚠ '} + +
({ + disconnectGasFeeEstimatePoller: jest.fn(), + getGasFeeEstimatesAndStartPolling: jest + .fn() + .mockImplementation(() => Promise.resolve()), + addPollingTokenToAppState: jest.fn(), +})); + const render = (props) => { const store = configureStore({ metamask: { @@ -15,10 +24,23 @@ const render = (props) => { useNativeCurrencyAsPrimaryCurrency: true, }, provider: {}, + cachedBalances: {}, + accounts: { + '0xAddress': { + address: '0xAddress', + balance: '0x176e5b6f173ebe66', + }, + }, + selectedAddress: '0xAddress', }, }); - return renderWithProvider(, store); + return renderWithProvider( + + + , + store, + ); }; describe('GasDetailsItem', () => { @@ -29,4 +51,14 @@ describe('GasDetailsItem', () => { expect(screen.queryByText('Max fee:')).toBeInTheDocument(); expect(screen.queryByText('ETH')).toBeInTheDocument(); }); + + it('should show warning icon if estimates are high', () => { + render({ defaultEstimateToUse: 'high' }); + expect(screen.queryByText('⚠ Max fee:')).toBeInTheDocument(); + }); + + it('should not show warning icon if estimates are not high', () => { + render({ defaultEstimateToUse: 'low' }); + expect(screen.queryByText('Max fee:')).toBeInTheDocument(); + }); }); diff --git a/ui/pages/confirm-transaction-base/low-priority-message/index.js b/ui/pages/confirm-transaction-base/low-priority-message/index.js new file mode 100644 index 000000000..7b2838d48 --- /dev/null +++ b/ui/pages/confirm-transaction-base/low-priority-message/index.js @@ -0,0 +1 @@ +export { default } from './low-priority-message'; diff --git a/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.js b/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.js new file mode 100644 index 000000000..41bb5d132 --- /dev/null +++ b/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.js @@ -0,0 +1,24 @@ +import React from 'react'; + +import ActionableMessage from '../../../components/ui/actionable-message/actionable-message'; +import { useGasFeeContext } from '../../../contexts/gasFee'; +import { useI18nContext } from '../../../hooks/useI18nContext'; + +const LowPriorityMessage = () => { + const { estimateToUse } = useGasFeeContext(); + const t = useI18nContext(); + + if (estimateToUse !== 'low') return null; + return ( +
+ +
+ ); +}; + +export default LowPriorityMessage; diff --git a/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.scss b/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.scss new file mode 100644 index 000000000..1a99a03af --- /dev/null +++ b/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.scss @@ -0,0 +1,3 @@ +.low-priority-message { + margin-top: 20px; +} diff --git a/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.test.js b/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.test.js new file mode 100644 index 000000000..9d8e233f3 --- /dev/null +++ b/ui/pages/confirm-transaction-base/low-priority-message/low-priority-message.test.js @@ -0,0 +1,59 @@ +import React from 'react'; + +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import { ETH } from '../../../helpers/constants/common'; +import { GasFeeContextProvider } from '../../../contexts/gasFee'; +import configureStore from '../../../store/store'; + +import LowPriorityMessage from './low-priority-message'; + +jest.mock('../../../store/actions', () => ({ + disconnectGasFeeEstimatePoller: jest.fn(), + getGasFeeEstimatesAndStartPolling: jest + .fn() + .mockImplementation(() => Promise.resolve()), + addPollingTokenToAppState: jest.fn(), +})); + +const render = (props) => { + const store = configureStore({ + metamask: { + nativeCurrency: ETH, + preferences: { + useNativeCurrencyAsPrimaryCurrency: true, + }, + provider: {}, + cachedBalances: {}, + accounts: { + '0xAddress': { + address: '0xAddress', + balance: '0x176e5b6f173ebe66', + }, + }, + selectedAddress: '0xAddress', + }, + }); + + return renderWithProvider( + + + , + store, + ); +}; + +describe('LowPriorityMessage', () => { + it('should returning warning message for low gas estimate', () => { + render({ transaction: { userFeeLevel: 'low' } }); + expect( + document.getElementsByClassName('actionable-message--warning'), + ).toHaveLength(1); + }); + + it('should return null for gas estimate other than low', () => { + render({ transaction: { userFeeLevel: 'high' } }); + expect( + document.getElementsByClassName('actionable-message--warning'), + ).toHaveLength(0); + }); +}); diff --git a/ui/pages/create-account/import-account/index.js b/ui/pages/create-account/import-account/index.js index 4f94f0965..d8003b4e9 100644 --- a/ui/pages/create-account/import-account/index.js +++ b/ui/pages/create-account/import-account/index.js @@ -41,7 +41,7 @@ export default class AccountImportSubview extends Component { return ( <>
-
Import Account
+
{t('importAccount')}
{t('importAccountMsg')} { - console.log('Added NFT'); + history.push(ADD_COLLECTIBLE_ROUTE); }} /> diff --git a/ui/pages/onboarding-flow/create-password/create-password.js b/ui/pages/onboarding-flow/create-password/create-password.js index 66471c67f..fcdbca69a 100644 --- a/ui/pages/onboarding-flow/create-password/create-password.js +++ b/ui/pages/onboarding-flow/create-password/create-password.js @@ -131,6 +131,7 @@ export default function CreatePassword({ >
setTermsChecked(!termsChecked)} checked={termsChecked} /> @@ -190,6 +193,11 @@ export default function CreatePassword({ - diff --git a/ui/pages/onboarding-flow/import-srp/import-srp.js b/ui/pages/onboarding-flow/import-srp/import-srp.js index f0b0c7c86..5d3f6b7f1 100644 --- a/ui/pages/onboarding-flow/import-srp/import-srp.js +++ b/ui/pages/onboarding-flow/import-srp/import-srp.js @@ -78,6 +78,7 @@ export default function ImportSRP({ submitSecretRecoveryPhrase }) { />